【问题标题】:Stop bot sending multiple requests quickly. PHP + AJAX停止机器人快速发送多个请求。 PHP + AJAX
【发布时间】:2015-06-23 16:17:27
【问题描述】:

我遇到了一个问题,他一直在用机器人利用我的投注网站。他能够(大概)使用机器人非常快速地多次按下“滚动”按钮并获得相同的滚动编号。

滚动按钮使用函数来工作。这是这个函数:

var rolling=false;
var lastBet=(Date.now()-<?php echo $settings['rolls_mintime']; ?>-1000);
function place(wager,multiplier,bot) {
  if ((rolling==false && (Date.now())>=(lastBet+<?php echo $settings['rolls_mintime']; ?>)) || bot==true) {
    rolling=true;
    lastBet=Date.now();
    $("#betBtn").html('ROLLING');
    if (bot!=true) _stats_content('my_bets');      
    $.ajax({
      'url': './content/ajax/place.php?w='+wager+'&m='+multiplier+'&hl='+under_over+'&_unique=<?php echo $unique; ?>',
      'dataType': "json",
      'success': function(data) {
        if (data['error']=='yes') {
          if (data['data']=='too_small') alert('Error: Your bet is too small.');
          if (data['data']=='invalid_bet') alert('Error: Your balance is too small for this bet.');
          if (data['data']=='invalid_m') alert('Error: Invalid multiplier.');
          if (data['data']=='invalid_hl') alert('Error: Invalid under/over specifier.');
if (data['data']=='invalid_bts') alert('Using bots, tut tut.');
          if (data['data']=='too_big_bet') alert('Error: Your bet is too big. Currently max profit is set at: '+data['under']+' this represents 1% of the invested backroll.');
        }
        else {
          var result=data['result'];
          var win_lose=data['win_lose'];
          if (win_lose==1) winCeremonial();
          else shameCeremonial();
        }

这个函数然后会导致 php 文件。这是它的标题:

if (empty($_GET['_unique']) || mysql_num_rows(mysql_query("SELECT `id` FROM `players` WHERE `hash`='".prot($_GET['_unique'])."' LIMIT 1"))==0) exit();

$playerinv=mysql_fetch_array(mysql_query("SELECT `id`,`playcoins`,`time`, `ex`, `server_seed` FROM `players` WHERE `hash`='".prot($_GET['_unique'])."' LIMIT 1"));
$random = base64_encode(openssl_random_pseudo_bytes(10));
$setstring = $random;
mysql_query("UPDATE `players` SET `string` = '$setstring' WHERE `id`=$playerinv[id] LIMIT 1");
$playersec=mysql_fetch_array(mysql_query("SELECT `string` FROM `players` WHERE `hash`='".prot($_GET['_unique'])."' LIMIT 1"));

if ($setstring != $playersec['string']) {
echo json_encode(array('error'=>'yes','data'=>'invalid_bts'));
exit();
}

$newSeed=generateServerSeed();
mysql_query("UPDATE `players` SET `server_seed`='$newSeed' WHERE `id`=$playerinv[id] LIMIT 1");

$settings=mysql_fetch_array(mysql_query("SELECT * FROM `system` LIMIT 1"));

$player=mysql_fetch_array(mysql_query("SELECT * FROM `players` WHERE `hash`='".prot($_GET['_unique'])."' LIMIT 1"));
$player['server_seed_']=$player['server_seed'];
$player['server_seed']=(double)substr($player['server_seed'],27);

正如您从一开始所看到的,我尝试通过生成一个专属于该运行的随机字符串 ($setstring)、存储它然后将其与自身进行比较来创建一个解决方法。然而不知何故,他设法以足够快的速度运行它,也克服了这个问题。

$newseed 是具有卷号的变量。如您所见,通常每次运行时都会生成一个新的。我通常对他如何做到这一点感到困惑,因为我认为每个 php 文件都是单独运行的。

谁能帮助提供一些见解或解决方案!例如,有人建议我使用事务封装,但不确定如何实现。感谢您抽出宝贵时间。

【问题讨论】:

  • 用验证码击败机器人

标签: php jquery mysql ajax bots


【解决方案1】:

我假设这种攻击是由于多线程而起作用的。由于随机交错,触发许多请求会使您的代码行为异常。

一个简单的例子是银行:

假设您想从您的帐户中扣除 20 美元:

$amount = q("SELECT * FROM accounts WHERE id = $account_id");
q("UPDATE accounts SET amount = $amount - 20 WHERE id = $account_id");

如果您以 100 美元开始,然后运行此代码两次,您预计最终会得到 60 美元。但是,如果线程交错发生在 select 和 update 调用之间,两个线程都将读取 100 美元,因此它们都将更新为 80 美元。

$setstring 的思路是正确的,但您需要更强大的东西。您需要查看锁定。

$lock = acquire_lock("foo");
$amount = q("SELECT * FROM accounts WHERE id = $account_id");
q("UPDATE accounts SET amount = $amount - 20 WHERE id = $account_id");
release_lock($lock);

锁可以通过多种方式实现。 PHP 甚至有一些特殊的功能和扩展。最简单的方法是使用文件锁。

function acquire_lock($name) {
    return fopen($name, "rw");
}
function release_lock($lock) {
    fclose($lock);
}

免责声明:我没有对此进行测试,我相信它应该在理论上可行:p

您可以使用以下脚本对此进行测试:

$lock = acquire_lock("foo");
sleep(30); // do nothing for 30 seconds
release_lock($lock);

然后尝试运行另一个脚本,该脚本也尝试获取foo 锁。它应该需要等待 30 秒。

【讨论】:

  • 我现在就试试这个。谢谢,这正是我一直在寻找的东西。 “rw”在第一个函数中的作用是什么?
  • 检查php.net/fopen 它以读写模式打开文件。我认为w 可能就足够了。也许只是r 也可以。这是我不确定的部分,需要测试;)
  • 这和去抖动的概念不一样吗?
  • 去抖类似于锁定,但不同之处在于它发生在服务器上,当涉及到安全性时,一切就不同了。所以是的,你基本上是在服务器上实现去抖动。
  • 啊,我明白了,客户端去抖动,服务器端锁定。谢谢:D
【解决方案2】:

您还可以在滚动按钮中实现simple debouncer using javascript,或易于实现的google captcha

【讨论】:

  • Debounce 会阻止您单击按钮,但不会阻止您发送请求。验证码可能太具有侵略性了。
  • 我认为这就是 OP 真正想要的,因为如果他想在滚动按钮上单击 1 次,为什么不在单击后禁用它??
  • 因为攻击者可能没有点击按钮。他只是发出请求,完全跳过按钮。你可以打开一个 JavaScript 控制台并执行:for (i = 0; i &lt; 100; i += 1){ $.ajax(/**/) } 来触发 100 个请求。如果攻击者更聪明,他甚至不会使用 JavaScript 进行攻击以绕过每个域的连接数限制。
  • 但他说:“我试图通过生成一个专属于该一次运行的随机字符串 ($setstring) 来创建一个变通方案”他不是在发送请求的页面中创建它吗?如果他这样做了,那么攻击者可能会在程序本身内进行 botting
  • 或者攻击者也可以生成字符串,所以他可以自动发送?
猜你喜欢
  • 2015-06-25
  • 1970-01-01
  • 1970-01-01
  • 2011-05-26
  • 1970-01-01
  • 2015-09-29
  • 1970-01-01
  • 2021-10-12
  • 1970-01-01
相关资源
最近更新 更多