JQuery — остановить бот, отправляющий несколько запросов быстро. PHP + AJAX

У меня проблема с кем-то, кто продолжает использовать мой сайт для ставок с ботом. Он может (предположительно) использовать бота, чтобы очень быстро несколько раз нажать кнопку «Roll» и получить одинаковые номера бросков.

Кнопка прокрутки с помощью функции для работы. Вот эта функция:

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-файл запускается отдельно.

Может ли кто-нибудь помочь предоставить некоторые идеи или решения! Мне предложили, например, инкапсуляцию транзакции, но я не уверен, как ее реализовать. Спасибо, что нашли время.

3

Решение

Я предполагаю, что эта атака работает из-за многопоточности. Выполнение многих запросов приведет к тому, что ваш код будет работать хаотично из-за случайного чередования.

Простой пример — банк:

Допустим, вы хотите вычесть 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 секунд.

4

Другие решения

Вы также можете реализовать простой debouncer, использующий JavaScript в вашей кнопке или легко внедрить гугл капча

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector