Защита от ботов, основанная на различии в работе с большими числами в JavaScript и PHP

Автор: skymotor 2021-6-16 Платное В» Модули и скрипты image Предлагаю Вашему вниманию телеграм бот обменника валюты. Хотите получать доход от обменов в телеграм? Тогда этот бот именно для Вас! imageОсобенности: Удобная админ панель; Обмен Яндекс Деньги, карты, Qiwi, криптовалюта; Установка комиссии обмена для каждой валюты; Редактирование текста и кнопок в админ панели; Партнерская программа 2 уровня ( процент можно менять); Управление историей заказов; Управление списком пользователей; Добавление автоматических ответов; Информация о заявке на обмен поступает в ваш телеграм, где вы можете подтвердить или отклонить обмен. Отзывы пользователей; И много другое! Обмены осуществляются в ручном режиме! Демо бота: Ознакомиться с ботом Доступ в админ панель предоставляю по запросу Установка: Инструкция по установке и настройке имеется. Могу сам установить и настроить. Стоимость: 10000 рублей Контакты: Телеграмм: Связаться Вконтакте: Связаться В Благодарностей: 5 sankdewa, thinkvn, vnwsxu, alexuain, bysany Просмотры: 1050 :: Комментарии (1) :: :: Нужна помощь? Задайте вопрос на форуме :: Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь. Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.Информация Посетители, находящиеся в группе Гости, не могут оставлять комментарии в данной новости. Скрипт бот для ВК, с помощью которого можно искать данные по базе данных + добавление в нее По команде /чек login ищет все данные по базе, выводя список результатов. Как настроить и запустить скрипт -> читайте эту статью Подойдет для изучения работы с базами данных и некоторыми видами массивов. Распространяется бесплатно  TREiV

Подключение к базе данных MySQL и работа с ней. Используем ее для ботов VK

5-04-2019, 20:16, Статьи / PHP

Работа с базой данных [phpMyAdmin] через RedBeanPHP

19-09-2019, 15:54, Статьи / PHP

Как создать бота Вконтакте с кнопками (keyboard)

1-04-2019, 23:36, Статьи / PHP

Cкрипт добавление возможных друзей Вконтакте, законная накрутка друзей без блокировок!

18-02-2020, 04:42, Статьи Материал из боты telegram – ebot.one – редактор ботов Перейти к: навигация, поиск

Внимание! Обновление от 2018.11.06 Прием данных теперь может осуществляться обоими методами (GET и POST) :)). Читаем тут

  • Ebot Server – библиотека для работы с редактором на стороне сервера. Если в разработке Вы используете внешние скрипты – эта библиотека создана для Вас.

Ниже идет описание примера внешнего скрипта без использования библиотеки Ebot Server (но мы рекомендуем использовать ее).

Видео с примером

Внешний скрипт должен лежать на хостинге (например, beget.com) и вернуть сериализованный в JSON массив с ключом ststus равным 1 и ключом body, в котором должен содержаться Ваш текст. Текст добавится к тому, который указан у команды в поле Текст. Если у команды в поле Текст ничего нет – то бот использует только данные, которые вернет скрипт, поэтому будте внимательны – если скрипт при этом тоже ничего не вернет – бот ничего не ответит пользователю.

Для некоторых операций во внешних скриптах требуется chat_id (ID в телеграме). Для того чтобы узнать свой id в телеграме достаточно написать своему или нашему (@bot_vprogramme_rf_bot) боту: getChatId

Переходим в настройки:

Для работы с внешним скриптом нам нужны будут вот эти значения:

В примере эти значения прописаны в теле самого скрипта, но если у Вас бот использует несколько файлов то имеет смысл вынести их, например в файл conf.php

Новый пример с получением данных можно скачать по ссылке.

Устаревший способ (его не поддерживают боты, созданные после 2018.03.24) можно посмотреть по ссылке

Читать на других языках: eng / deu

В Telegram появился бот под названием MailSearchBot, который собирает все известные утечки баз данных. С помощью него вы можете узнать, не попал ли один из ваших паролей в открытый доступ.

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

Хакеры могут взламывать аккаунты в различных сервисах методом перебора всех доступных им данных. Поэтому если вы увидите в списке пароль, который до сих пор используете в почте либо где-то ещё, то лучше смените его.

Автор бота Батыржан Тютеев рассказал, что сейчас в базе находится около девяти миллиардов записей. Ещё три миллиарда будут загружены в скором времени.

Запустить бота →

Информационная безопасность* Из песочницы Недавно мне пришлось разбираться с защитой от ботов, используемой на нескольких довольно популярных ресурсах. На первый взгляд защита показалась обычной установкой куки через javascript, справиться с которой — дело 15-ти минут. В самом деле, после небольшого исследования стало понятно где что делается и какие параметры куда передаются, остается только переписать небольшую функцию с javascript на php и дело в шляпе. Но все оказалось не так просто. И хотя в итоге защита была сломана, на это потребовалось далеко не 15 минут, и сам принцип защиты оказался для меня новым и довольно интересным. Итак, обо всем по порядку.

Поверхностный осмотр

Защита работает следующим образом. Скрипт главной страницы сайта index.php ожидает куку, в которой одним из параметров будет указан хеш, вычисленный из IP-адреса посетителя. Если кука не передается, то index.php перенаправляет посетителя на другую страницу, содержащую javascript код, который вычисляет необходимый параметр, записывает его в куку и возвращает нас обратно на главную страницу. Чтобы обычный php-бот, выполняющий GET и POST запросы через CURL, смог проходить через такую защиту, нужно переписать вычисление хеша с javascript на php и затем дописывать в заголовок запроса нужную куку.

Вскрытие

Теперь подробнее. Запускаем Firefox, отключаем javascript и включаем Firebug. Запрашиваем главную страницу index.php и смотрим заголовки запроса и ответа. Запрос: GET

http://example.com

Заголовки этого запроса не представляют для нас интереса. А вот заголовки ответа: Status: 302 Moved Temporarily Connection keep-alive Content-Type text/html Date XXX GMT Location http://example.com/govalidateyourself#98765:1234:11.22.33.44:/index.php Server YTS/1.20.0 Transfer-Encoding chunked После чего Firefox автоматически переходит на указанный в заголовке Location, получая следующий заголовок ответа: Accept-Ranges bytes Connection keep-alive Content-Type text/html; charset=utf-8 Date XXX GMT Last-Modified YYY GMT Server YTS/1.20.0 Set-Cookie addr=1234:11.22.33.44; path=/ Transfer-Encoding chunked Где 11.22.33.44 — мой IP-адрес, 1234 — какое-то число, логика вычисления которого неизвестна. Сама страница содержит ссылку на js-код

http://example2.com/validator/va.js

и надпись «No javascript». Без js нас дальше не пустят. После того как все запросы-ответы записаны, включаем javascript, очищаем cookie и делаем все заново. Сейчас нас интересует то, что будет происходить после запроса страницы валидации. На этот раз загружается главная страница сайта, и вот заголовок последнего запроса: Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding gzip, deflate Accept-Language ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3 Connection keep-alive Cookie addr=5678:11.22.33.44; urine=aabbccdd; v=1 Host example.com Referer http://example.com/govalidateyourself User-Agent какой-то Firefox Константа 1234 из прошлого ответа сервера в этот раз изменилась на 5678, IP-адрес остался тем же. Судя по всему это ID запроса, присваиваемый сервером и хранящийся в cookie. Ну что ж, его надо сохранить и просто записывать в куки в неизменном виде во время запросов. А вот параметр urine=aabbccdd — это уже интересно. Раз он не приходил от сервера — значит он был получен у нас, и что-то подсказывает мне что это дело рук va.js. Самое время посмотреть что там внутри. На первый взгляд полное болото, в которое лучше не влезать:

if(document.cookie==""){document.write("Cookies error")}else{function poo(a,b){var c=a.length,d=b^c,e=0,f;while(c>=4){f=a.charCodeAt(e)&255|(a.charCodeAt(++e)&255)<<8|(a.charCodeAt(++e)&255)<<16|(a.charCodeAt(++e)&255)<<24;f=(f&65535)*1540483477+(((f>>>16)*1540483477&65535)<<16);f^=f>>>24;f=(f&65535)*1540483477+(((f>>>16)*1540483477&65535)<<16);d=(d&65535)*1540483477+(((d>>>16)*1540483477&65535)<<16)^f;c-=4;++e}switch(c){case 3:d^=(a.charCodeAt(e+2)&255)<<16;case 2:d^=(a.charCodeAt(e+1)&255)<<8;case 1:d^=a.charCodeAt(e)&255;d=(d&65535)*1540483477+(((d>>>16)*1540483477&65535)<<16)}d^=d>>>13;d=(d&65535)*1540483477+(((d>>>16)*1540483477&65535)<<16);d^=d>>>15;return d>>>0}function coo(a){var b=a+"=";var c=document.cookie.split(";");for(var d=0;d=3){document.write("Too many redirects from: "+document.referrer)}} 

Но немного терпения, и после форматирования все выглядит читабельно и довольно понятно. Есть две функции coo() и poo(), и код который пишет нужную нам куку и отправляет обратно на index.php. Функция сoo() не представляет особого интереса, она получает значение указанного параметра из куки, и легко переписывается на php простым регулярным выражением. А вот функция poo(), которая считает параметр urine:

 function poo( a, b ) {    var c = a.length, d = b^c, e = 0, f;     while( c >= 4 )    {       f = a.charCodeAt( e ) & 255 | ( a.charCodeAt( ++e ) & 255 ) << 8 | ( a.charCodeAt( ++e ) & 255 ) << 16 | ( a.charCodeAt( ++e ) & 255 ) << 24;        f = ( f & 65535 ) * 1540483477 + ( ( ( f >>> 16 ) * 1540483477 & 65535 ) << 16 );       f ^= f >>> 24;        f = ( f & 65535 ) * 1540483477 + ( ( ( f >>> 16 ) * 1540483477 & 65535 ) << 16 );        d = ( d & 65535 ) * 1540483477 + ( ( ( d >>> 16 ) * 1540483477 & 65535 ) << 16 )^f;        c -= 4;        ++e    }     switch( c )    {       case 3:          d ^= ( a.charCodeAt( e + 2 ) & 255 ) << 16;        case 2:          d ^= ( a.charCodeAt( e + 1 ) & 255 ) << 8;        case 1:          d ^= a.charCodeAt( e ) & 255;        d = ( d & 65535 ) * 1540483477 + ( ( ( d >>> 16 ) * 1540483477 & 65535 ) << 16 )    }     d ^= d >>> 13;     d = ( d & 65535 ) * 1540483477 + ( ( ( d >>> 16 ) * 1540483477 & 65535 ) << 16 );    d ^= d >>> 15;     return d >>> 0 }  

Во время вызова ей передаются такие параметры:

var a = poo( addr, 47 ).toString( 16 ); 

a — это и есть уже готовое значение параметра urine (дальше оно только дополняется нулями если содержит меньше 8 символов). addr — наш IP-адрес 11.22.33.44. 47 — константа. Теперь все выглядит понятно. php-бот, пробивающий эту защиту, должен работать по следующему алгоритму. 1. Делаем GET-запрос

http://example.com/index.php

Cтавим опцию получать заголовки ответа:

curl_setopt( $ch, CURLOPT_HEADER, 1 ); 

И заодно включаем автоматический переход в случае редиректа:

curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, 1 ); 

В этом случае curl сам выполнит переход на новый location, и нам нет нужды программировать второй запрос. И мы получим заголовки обоих ответов, в первом заголовке будет Location, во втором — первая кука, содержащая ID запроса. 2. Парсим заголовки, получаем ID запроса и свой IP-адрес (если мы используем разные трюки то мы можем его сразу и не знать, а здесь его нам любезно подсказывают — очень удобно). Считаем параметр urine, записываем в куку и отправляем новый GET-запрос на index.php. Защита пройдена. Кука прописывается так:

$headers = array(    "Cookie: " . $cookie_str, // "addr=5678:11.22.33.44; urine=aabbccdd; v=1"    /* другие заголовки по желанию/необходимости */ );  curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers ); 

Итак, остался последний штрих — вычисление urine.

Грабли

Нужно просто переписать функцию poo() на php. Для начала немного гуглим и пишем аналоги для пары js-функций и операторов, которых нет в php:

// php js functions function charCodeAt( $str, $i ) {    return ord( substr( $str, $i, 1 ) ); }  // char at function charAt( $str, $i ) {    return $str{ $i }; }  //unsigned shift right (js >>>) function zeroFill( $a, $b ) {     $z = hexdec( 80000000 );      if( $z & $a )     {        $a = ( $a >> 1 );        $a &= ( ~ $z );        $a |= 0x40000000;        $a = ( $a >> ( $b - 1 ) );     }     else     {        $a = ( $a >> $b );     }      return $a;  }  

Теперь все готово, и можно переписать poo():

// function poo( $a, $b ) {    $c = strlen( $a );    $d = $b ^ $c;    $e = 0;    $f = '';     while( $c >= 4 )    {       $f = charCodeAt( $a, $e ) & 255 | ( charCodeAt( $a, ++$e ) & 255 ) << 8 |          ( charCodeAt( $a, ++$e ) & 255 ) << 16 | ( charCodeAt( $a, ++$e ) & 255 ) << 24;        $f = ( $f & 65535 ) * 1540483477 + ( ( ( zeroFill( $f, 16 ) ) * 1540483477 & 65535 ) << 16 );       $f ^= zeroFill( $f, 24 );        $f = ( $f & 65535 ) * 1540483477 + ( ( ( zeroFill( $f, 16 ) ) * 1540483477 & 65535 ) << 16 );        $d = ( $d & 65535 ) * 1540483477 + ( ( ( zeroFill( $d, 16 ) ) * 1540483477 & 65535 ) << 16 )^$f;        $c -= 4;        ++$e;    }     switch( $c )    {       case 3:          $d ^= ( charCodeAt( $a, $e + 2 ) & 255 ) << 16;        case 2:          $d ^= ( charCodeAt( $a, $e + 1 ) & 255 ) << 8;        case 1:          $d ^= charCodeAt( $a, $e ) & 255;        $d = ( $d & 65535 ) * 1540483477 + ( ( ( zeroFill( $d, 16 ) ) * 1540483477 & 65535 ) << 16 );    }     $d ^= zeroFill( $d, 13 );     $d = ( $d & 65535 ) * 1540483477 + ( ( ( zeroFill( $d, 16 ) ) * 1540483477 & 65535 ) << 16 );    $d ^= zeroFill( $d, 15 );     return zeroFill( $d, 0 ); } </code>

Сохраняем, запускаем и обламываемся — результаты js и php версий не совпадают. В чем дело? Добавляем код в js и php для вывода результата после каждой строки вычислений и смотрим в чем дело. Оказывается простые арифметические операторы php в отличие от javascript плохо умеют работать с большими числами. Например выражение

( 18220025198660 & 65535 ) * 1540483477 + ( ( ( 18220025198660 >>> 16 ) * 1540483477 & 65535 ) << 16 ); </code>

в javascript будет равно 22188624159636, а аналогичное в php

( 18220025198660 & 65535 ) * 1540483477 + ( ( ( zeroFill( 18220025198660, 16 ) ) * 1540483477 & 65535 ) << 16 ) </code>

будет равно немного другому числу 22188624159600 Когда несколько подобных формул вычисляются подряд то ошибка накапливается, давая в итоге совсем другой результат. В некоторых выражениях php по умолчанию предполагает что результат является типом int и ограничивает максимальное значение до 4 млрд (на 32-х разрядных системах). Похожие проблемы с большими числами есть и у Perl. Для точных вычислений в php необходимо использовать функции библиотеки BC Math. Вместе с этим нужно добавить приведение к типу float. В результате проб и ошибок получаем код, дающий те же результаты что и javascript. Но это требует дополнительных времени и усилий. Код не самый оптимальный, для большей ясности вычисления выполняются по шагам.

// function poo( $a, $b ) {    $c = strlen( $a );    $d = $b ^ $c;    $e = 0;    $f = '';     while( $c >= 4 )    {       $f = charCodeAt( $a, $e ) & 255 | ( charCodeAt( $a, ++$e ) & 255 ) << 8 |          ( charCodeAt( $a, ++$e ) & 255 ) << 16 | ( charCodeAt( $a, ++$e ) & 255 ) << 24;        $f = bcadd( bcmul( $f & 65535, 1540483477 ), ( floatval( ( bcmul( ( zeroFill( $f, 16 ) ), ( 1540483477 & 65535 ) ) ) ) << 16 ) );        $xx = zeroFill( $f, 24 );        $f = floatval( $f ) ^ floatval( $xx );        //       $f = floatval( $f );        $f1 = bcmul( $f & 65535, 1540483477 );       $f2 = ( floatval( ( bcmul( ( zeroFill( $f, 16 ) ), ( 1540483477 & 65535 ) ) ) ) << 16 );        $f = bcadd( $f1, $f2 );        $d1 = bcmul( $d & 65535, 1540483477 );       $d2 = ( floatval( ( bcmul( ( zeroFill( $d, 16 ) ), ( 1540483477 & 65535 ) ) ) ) << 16 );        $d = bcadd( $d1, $d2 );       $d = floatval( $d ) ^ floatval( $f );        $c -= 4;        ++$e;    }     switch( $c )    {       case 3:          $d = floatval( $d ) ^ ( ( charCodeAt( $a, $e + 2 ) & 255 ) << 16 );        case 2:          $d = floatval( $d ) ^ ( ( charCodeAt( $a, $e + 1 ) & 255 ) << 8 );        case 1:          $d = floatval( $d ) ^ ( charCodeAt( $a, $e ) & 255 );           $d1 = bcmul( $d & 65535, 1540483477 );          $d2 = ( floatval( ( bcmul( ( zeroFill( $d, 16 ) ), ( 1540483477 & 65535 ) ) ) ) << 16 );           $d = bcadd( $d1, $d2 );    }     $d = floatval( $d ) ^ zeroFill( $d, 13 );     $d1 = bcmul( floatval( floatval( $d ) & 65535 ), 1540483477 );    $dd21 = zeroFill( $d, 16 );    $dd22 = floatval( bcmul( $dd21, 1540483477 & 65535 ) );    $dd23 = floatval( $dd22 << 16 );    $d2 = $dd23;     $d = bcadd( $d1, $d2 );     $d = floatval( $d ) ^ zeroFill( $d, 15 );     if( $d < 0 )    {       $res = bindec( decbin( ~0 ) ) - abs( $d ) + 1;    }    else    {       $res = $d;    }     return $res; } </code>

И для функции zeroFill() добавляем в самое начало:

$a = floatval( $a ); 

Заключение

Мои боты свое дело сделали, а вы можете использовать описанную здесь защиту в своих целях. Если ее модифицировать, например динамически менять делающий вычисления код, то подобный взлом станет еще более трудной задачей. И если за вас никто не захочет взяться всерьез то этой защиты будет достаточно. А вообще, лучшая защита от ботов — это капча. Даже самый хитрый javascript может быть выполнен ботами, использующими что-нибудь типа Perl-модуля Mechanize.

Оцените статью
Рейтинг автора
4,8
Материал подготовил
Максим Коновалов
Наш эксперт
Написано статей
127
А как считаете Вы?
Напишите в комментариях, что вы думаете – согласны
ли со статьей или есть что добавить?
Добавить комментарий