停止bot快速发送多个请求。 PHP + AJAX

时间:2015-04-17 01:18:53

标签: php jquery mysql ajax bots

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

使用功能工作的滚动按钮。这是这个功能:

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文件都是单独运行的。

任何人都可以帮助提供一些见解或解决方案!我曾建议使用事务封装,但不知道如何实现。感谢您抽出宝贵时间。

2 个答案:

答案 0 :(得分:4)

我假设这种攻击因多线程而起作用。解雇许多请求会使您的代码因随机交错而表现不正常。

一个简单的例子是银行:

假设您想从您的帐户中扣除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秒。

答案 1 :(得分:0)

您还可以在自动滚动按钮中实施simple debouncer using javascript,或轻松实施google captcha