Pull to refresh

Запрещаем использование известных UserJS

Reading time4 min
Views2K

Введение


UserJS предоставляет пользователям удобный и простой механизм модификации веб-страниц, именно благодаря этому многие пользователи автоматизирую свои действия с помощью UserJS, а иногда и обходят слабые системы защиты.
Больше всего от использования UserJS пользователями страдают браузерные онлайн-игры, многие из которых уже начали войну против UserJS. Так, например, в игре Travian используются поддельные скрытые веб-формы, которые иногда появляются вместе с обычными, UserJS-скрипты, написанные без учета этой особенности, ошибаются и отправляют данные через фэйковую форму, за что игрок немедленно получает наказание.
Хотелось бы сразу отметить, что бороться можно только с известными UserJS-скриптами, показанное решение не универсально и не может защитить от любого скрипта.
Сегодня я представляю на ваш суд свой метод борьбы с пользовательскими скриптами — MD5-хэширование с последующим сравнением. Основные действующие роли играют JavaScript и PHP.

Легенда


Предположим, у нас есть веб-сайт с простой формой авторизации, но пользователи повадились не вводить свой логин, а использовать UserJS-скрипт, который добавляет в форму дополнительную кнопку, нажатие на которую автоматически вводит их логин. Этот пример взят просто для наглядности, на месте формы авторизации может быть, например, форма отправки войск в онлайн-стратегии, а UserJS-скрипт — бот, автоматически рассылающий войска.

Исходные данные


Итак, наша форма выглядит так:


Пользователи используют следующий UserJS в браузере Opera:
Copy Source | Copy HTML
  1. window.opera.addEventListener('AfterEvent.load', function (e){
  2.     if (e.event.target instanceof Document){
  3.               e.preventDefault();
  4.         document.forms[ 0].innerHTML+='<input type="button" onclick="document.forms[0].login.value=\'Login\';" value="AutoLogin">';
  5.         }
  6. },false);


Или в FireFox для расширения GreaceMonkey:
Copy Source | Copy HTML
  1. // ==UserScript==
  2. // @name           test1
  3. // @namespace      test
  4. // @include        http://localhost/anti-userjs/test1.php
  5. // ==/UserScript==
  6.  
  7. document.forms[ 0].innerHTML+='<input type="button" onclick="document.forms[0].login.value=\'Login\';" value="AutoLogin">';


После включения этого скрипта пользователи получают такой вид формы авторизации:


Нажатие на кнопку «AutoLogin», как видно из исходных текстов, приводит к заполнению поля «login».
Попробуем запретить пользователем использование этого скрипта.

Вывод формы авторизации


Выводить форму авторизации мы будем из PHP-файла, обрамим форму тегом div, а также захешируем все данные внутри этого тега средствами PHP. Хеш сохраним в сессии для последующего контроля:
Copy Source | Copy HTML
  1. <div id="main">
  2. <?
  3. ob_start();
  4. ?>
  5. <form method="POST">
  6. Логин: <input name="login" type="text"><br>
  7. Пароль: <input name="password" type="password" ><br>
  8. <input name="md5" type="hidden"><br>
  9. <input value="Войти" type="submit">
  10. </form>
  11. <?
  12. $data=ob_get_contents();
  13. ob_end_flush();
  14. $data=strtr($data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz');
  15. $data=preg_replace("/[ \t\n\r]/",'',$data);
  16. $md5=md5($data);
  17. $_SESSION['md5']=$md5;
  18. ?></div>


Пара слов про обработку содержимого — браузеры Opera и FireFox по-своему изгаляются над HTML-кодом, поэтому обработка его через JavaScript приводит к разным результатам. Так, Opera приводит все HTML-теги к заглавным буквам, а FireFox меняет параметры в тегах по стандарту. Поэтому важно валидно писать контролируемый HTML-код.
Для устранения различной обработки регистра тегов и переноса строк из содержимого удаляются все пробелы, табуляции и переносы строк, а также все английские буквы приводятся в нижний регистр.
Еще одно важное замечание — кодировка документа должна быть UTF-8, с CP1251 JavaScript в браузерах и PHP работаю по-разному.

Контроль через JavaScript


Итак, форма выведена, её контрольная сумма сосчитана, теперь нужно посчитать её со стороны пользователя и убедится, что вмешательства UserJS не было. Для этого мы добавляем событие на onLoad и вызываем JS-функцию:
Copy Source | Copy HTML
  1. >
  2. function checkuserjs(){
  3.     var data=document.getElementsByTagName('div')[ 0].innerHTML;
  4.     data=strtr(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz');
  5.     data=data.replace(/[ \t\n\r]/g,'');
  6.     document.forms[ 0].md5.value=md5(data);
  7. }

 


В ней я использовал несколько готовых функций — md5 и strtr, я не буду выкладывать их в статье, вы сможете найти их в приложенном файле.
Java-Script на стороне пользователя выполняет те же самые действия, что и PHP-скрипт выше, результат — хэш содержимого — заносится в форму.

Обработка на стороне сервера


Дело остается за малым — проверить полученные данные:
Copy Source | Copy HTML
  1. if ($_POST){
  2.     if ($_POST['md5']!=$_SESSION['md5'])
  3.         die ('Использование UserJS запрещено!');
  4.     echo 'Форма отправлена';
  5. }


Таким образом мы отлавливаем недобросовестных пользователей (обратите внимание на индикатор GreaseMonkey):


Заключение


Указанный мной пример демонстрирует сам подход к запрещению использования UserJS, при разработке решений на его основе нужно понять основной момент — запретить использование любого UserJS не возможно, поэтому нужно отслеживать выкладываемые скрипты, затрагивающие наши сайты, и вырабатывать защиту от них. Так как делаются такие скрипты на энтузиазме, велик шанс, что новая версия скрипта, обходящая нашу защиту, если и выйдет, то не скоро. Тот же Травиан это демонстрирует — простейшая защита с фэйковыми формами введена пол-года назад, до сих пор нет новой версии UserJS-скриптов.

Приложение: anti-userjs.tar.gz 3708 bytes
Tags:
Hubs:
Total votes 5: ↑2 and ↓3-1
Comments9

Articles