停止漫游器快速发送多个请求. PHP AJAX

我遇到一个人,这个人一直在用机器人利用我的博彩网站.他能够(大概)使用漫游器非常快速地多次按下“滚动”按钮并获得相同的掷骰数.

使用滚动按钮可以正常工作的功能.这是这个功能

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)专有的随机字符串($setstring),存储它,然后将其与自身进行比较来创建一种变通方法.无论如何,他设法使其运行得足够快,以至于无法通过.

$newseed是具有转数的变量.如您所见,通常在每个运行时生成一个新的.我通常对他如何做到这一点感到困惑,因为我认为每个PHP文件都单独运行.

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

解决方法:

我假设这种攻击有效是因为多线程.发出许多请求将使您的代码由于随机交织而无法正常工作.

一个简单的例子是银行:

假设您要从帐户中扣除$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秒.

相关文章

IE6是一个非常老旧的网页浏览器,虽然现在很少人再使用它,但...
PHP中的count()函数是用来计算数组或容器中元素的个数。这个...
使用 AJAX(Asynchronous JavaScript and XML)技术可以在不...
Ajax(Asynchronous JavaScript and XML)是一种用于改进网页...
本文将介绍如何通过AJAX下载Excel文件流。通过AJAX,我们可以...
Ajax是一种用于客户端和服务器之间的异步通信技术。通过Ajax...