Избавление от KAPTCHA, раз и на всегда
	
	
	                
  
  
  
  
		Фразы «введите символы с картинки» начали всех уже не просто доставать, а их не читабельность, ну просто выводит из себя. Примерно с полгода назад я задумался а как можно обойтись без нее и все оказалось гораздо проще чем можно представить. Ну для начала посмотрим в историю, от куда появились «каптчи» и зачем — ответ очевиден, для того, что-бы избавиться от роботов разного уровня. Исходя из данного можно подумать теперь над другим: ботов пишут для сайтов типа форумы, блоги, т.е. тех куда можно в свободной и бесплатной форме запостить рекламное сообщение. Посмотрим на это со стороны «бото-писца», как пишут ботов?:
Можно понять, что сгенеренные поля или еще какие уловки хороший бот может отловить сразу, но все думают что каптчу то не сможет. В принципе «каптчу» отловить тяжело, для этого нужен либо алгоритм хеширования символов, но как правило используется не обратимый — такой метод не подходит, читать саму картинку — знавал человека который сделал сканер картинок, но не всем такое дано, использовать сервисы которые предлагают распознавать картинки — идеально. Вывод напрашивается сам: «каптча» не панацея, кому нужно, тот и ее пройдет, тогда зачем нам, разработчикам напрягать пользователей? Ну без защиты боты регаются и постятся в не малых количествах… Вот тут и появилась задача, для решения данной проблемы. Итак мы знаем что боты не умеют:
Исходя из такого громадного наличия инструментов, можно сделать свой алгоритм доступа. Не претендую стать первым и самым умным в данном вопросе, но пока что, данной технологии не встречал ни где, кроме своих сайтов и сайтов моих клиентов, разумеется. Начнем создавать «антибот» систему, в примере буду приводить выдержки кода с применением ZF и Doctrine
Итак, для начала мы создадим таблицу для временных записей, обзовем ее скажем так:
так же создадим файлик для AJAXa — fish.phtml, с содержанием
(«разумееться с проверкой в контроллере if ($this->_request->isXmlHttpRequest()){»):
Вернемся к форме регистрации или свободного поста, неважно к какой форме… но она должна иметь вот такую вставку:
ну и перейдя в саму форму добавим вот такое вот поле:
В принципе все, остался только AJAX обработчик, напишем и его:
Пошел наш субмит, поясню что происходит в посте на примере. Мы зашли на страницу с формой, послее ее загрузки у нас образовалась запись в базе:
unic_id = 44958
hash = 03cf63bea12bfcd3644846baa8481d07
mask = 4ca388cf
time_cr = 1285785784
ip = ххх.ххх.ххх.ххх
Далее мы записываем инпут с содержанием лишь одного ориентира:
После нажатия на кнопку «субмит» и обработки JS в форму были добавлены следующие параметры:
form action="/register/?crast=44958"
ну и соответственно это все послыается постом на адрес xxx/register/crast=44958, что же происходит в обработчике поста, рассмотрим:
В общем все, теперь смотрим у себя в проверках и выполняем нужные нам функции для регистрации, постинга и т.д.
Итоги: мы получили «защитника» от ботов, простым без «капчевым» путем.
Предугадываю некоторые нападения разъясню:
«Выполнять JS» — да это так, JS можно с эмулировать, но не факт что эмулированный JS выдаст нужные результаты
«Читать базу» — в нашем примере, JS служит лишь для замены и вызова параметров из таблицы, а они у нас генеряться фоном при загрузке, а т.к. их нет не на странице ни в заголовках, то их определить очень проблематично. То что вставка происходит на лету, этого бот отловить не сможет, а если и сможет, то тому мастеру который это сделает, ну просто не нужен будет Ваш форму или блог или еще что по проще, ему по зубам будет система безопасности банк-клиентов :-)
 
				
	  
- Анализируют сайт
- Смотрят все формы и методы, куда и какие поля передаются
- Формируют агрегатор с использованием курлов либо сокетов
- Тестируют агрегатор на предмет отлавливания каких либо дополнительных полей
- Уже после этого запускают, наслаждаясь жизни
Можно понять, что сгенеренные поля или еще какие уловки хороший бот может отловить сразу, но все думают что каптчу то не сможет. В принципе «каптчу» отловить тяжело, для этого нужен либо алгоритм хеширования символов, но как правило используется не обратимый — такой метод не подходит, читать саму картинку — знавал человека который сделал сканер картинок, но не всем такое дано, использовать сервисы которые предлагают распознавать картинки — идеально. Вывод напрашивается сам: «каптча» не панацея, кому нужно, тот и ее пройдет, тогда зачем нам, разработчикам напрягать пользователей? Ну без защиты боты регаются и постятся в не малых количествах… Вот тут и появилась задача, для решения данной проблемы. Итак мы знаем что боты не умеют:
- Выполнять JS
- Формировать XmlHTTPRequest
- Читать базу — доступ до нее ни кто не даст
Исходя из такого громадного наличия инструментов, можно сделать свой алгоритм доступа. Не претендую стать первым и самым умным в данном вопросе, но пока что, данной технологии не встречал ни где, кроме своих сайтов и сайтов моих клиентов, разумеется. Начнем создавать «антибот» систему, в примере буду приводить выдержки кода с применением ZF и Doctrine
Итак, для начала мы создадим таблицу для временных записей, обзовем ее скажем так:
Antibot (
  id - bigint(20)
  unic_id - varchar(10)
  hash - varchar(50)
  mask - varchar(10))
  time_cr - bigint(20)
  ip - varchar(20)
);так же создадим файлик для AJAXa — fish.phtml, с содержанием
(«разумееться с проверкой в контроллере if ($this->_request->isXmlHttpRequest()){»):
$tmp_data = Doctrine_Query::create()
    ->select('*')
    ->from('Antibot')
    ->where('unic_id = ?', $this->data)
    ->execute()
    ->toArray();
// эти данные нам нужны будут для вывода и замены данных в форме, об этом ниже
echo $tmp_data[0]['mask']."|||".$tmp_data[0]['hash']."|||gogo";Вернемся к форме регистрации или свободного поста, неважно к какой форме… но она должна иметь вот такую вставку:
// ориентир, время, метка
$crast = dechex(time()+rand(00,99));
 
// Функция рендома символов
   function random_simbols() {
/* тут может быть любой агрегатор рендомайзинга символов, зависит от вашей фантазии */
   }
 
/* получаем ip посетителя, таким методом мы получим ip в любом случае и в любом это будет именно ip без проксей */
   if (! function_exists('getenv')) {
      $client_ip = $HTTP_SERVER_VARS['HTTP_CLIENT_IP'];
      $x_frd_for = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'];
      $rmte_addr = $HTTP_SERVER_VARS['REMOTE_ADDR'];
   } else {
      $client_ip = getenv('HTTP_CLIENT_IP');
      $x_frd_for = getenv('HTTP_X_FORWARDED_FOR');
      $rmte_addr = getenv('REMOTE_ADDR');
   }
   if ($client_ip) {
      $x_cip = explode(".", $client_ip);
      $x_rmt = explode(".", $rmte_addr);
      $ip = ($x_cip['0'] != $x_rmt['0']) ? implode(".", array_reverse($x_cip)) : $client_ip;
   } elseif ($x_frd_for) {
      $ip = (strstr($x_frd_for, ",")) ? end(explode(",", $x_frd_for)) : $x_frd_for;
   } else {
      $ip = $rmte_addr;
   }
 
   $mask = explode(".", $ip);
 
// создадим херню полную - извините за выражения, но оно так и есть
   $unic_id = $mask[0] * ($mask[1] + $mask[2] + $mask[3] + rand(000,999));
 
// создадим хеш для сравнения, потом пригодиться 
   $hash = md5($unic_id."".random_simbols()."".$crast);
 
// создаем временную запись, в нашей антибот таблице
   $thmdata = new Antibot();
   $thmdata->unic_id = $unic_id;
   $thmdata->hash = $hash;
   $thmdata->mask = $crast;
   $thmdata->time_cr = time();
   $thmdata->ip = $ip;
   $thmdata->save();ну и перейдя в саму форму добавим вот такое вот поле:
<input type="hidden" value="<?=$unic_id?>" id="crast" />В принципе все, остался только AJAX обработчик, напишем и его:
<script>
$(document).ready(function(){
 
// Повешаем событие на обработку кнопки субмита
   $('#submit').click(function(){
      doitnow='stop';
      $.ajax({
         type:"GET",
 
   // Обратимся к нашему файлику, который создали вначале
         url:"/index/fish/",
         data:"data="+$('#crast').val(),
 
   // Очень важная штука, без нее запрос будет выполняться не последовательно!
         async:false,
 
   // Если запрос прошел хорошо, т.е. AJAX выполнился действуем по нашим правилам
         success:function(msg){
 
    // Вот это, мы как раз и получаем из "фиша" и из полученных данных составляем свои
            msg=msg.split("|||");
            doitnow=msg[2];
 
   // Помните, выше мы добавили в форму инпут, вот мы меняем ему имя и значения на лету, для минимилизации перехвата
            $('#crast').attr({name:msg[0],value:msg[1]});
 
   // Добавим к акшену формы дополнительный параметр
            $("form").attr('action',$("form").attr('action')+'/?crast='+$('#crast').attr('name'));
 
   // Закончили изваращаться над формой и элемента, пора в путь, жмем субмит
            $("form").submit(function(){
               if(doitnow=='gogo'){
                  return true;
               }return false;
            });
         },error:function(){
            alert('Произошла ошибка, нажмите "Вход в систему" еще раз');
         return false;
      }});
   });
});
</script>Пошел наш субмит, поясню что происходит в посте на примере. Мы зашли на страницу с формой, послее ее загрузки у нас образовалась запись в базе:
unic_id = 44958
hash = 03cf63bea12bfcd3644846baa8481d07
mask = 4ca388cf
time_cr = 1285785784
ip = ххх.ххх.ххх.ххх
Далее мы записываем инпут с содержанием лишь одного ориентира:
<input type="hidden" id="crast" value="44958">После нажатия на кнопку «субмит» и обработки JS в форму были добавлены следующие параметры:
form action="/register/?crast=44958"
<input type="hidden" id="crast" name="4ca388cf" value="03cf63bea12bfcd3644846baa8481d07">ну и соответственно это все послыается постом на адрес xxx/register/crast=44958, что же происходит в обработчике поста, рассмотрим:
// Если данный парам CRAST пустой значит пост искуственный
   if ($_GET['crast'] == '') {
      $error = "Вы наверное бот :-)";
 
        // удалим нашу временную запись, что бы потом не смогли к ней обратиться
                $tmp_data = Doctrine_Query::create()
                 ->delete()
                 ->from('Antibot')
                 ->where('mask = ?', $_GET['crast'])
                 ->execute();
   } else {
// Возьмем данные из таблицы для сравнения
      $tmp_data = Doctrine_Query::create()
            ->from('Antibot')
            ->where('mask = ?', $_GET['crast'])
            ->execute()
            ->toArray();
   }
 
// Сравниваем полученные данные из таблицы и из поста, на их соответствие, вдруг их нагенерили свим способом, такое тоже возможно
if ($this->_request->getPost ($_GET['crast']) != $tmp_data[0]['hash']) { 
    // отловилась ошибка это робот
    $error = "yes";
// удалим нашу временную запись, что бы потом не смогли к ней обратиться
                $tmp_data = Doctrine_Query::create()
                 ->delete()
                 ->from('Antibot')
                 ->where('mask = ?', $_GET['crast'])
                 ->execute();
} else {
   // скорее всего это человеческий пост
    $error = "no";
// удалим нашу временную запись, что бы потом не смогли к ней обратиться
                $tmp_data = Doctrine_Query::create()
                 ->delete()
                 ->from('Antibot')
                 ->where('mask = ?', $_GET['crast'])
                 ->execute();
}В общем все, теперь смотрим у себя в проверках и выполняем нужные нам функции для регистрации, постинга и т.д.
Итоги: мы получили «защитника» от ботов, простым без «капчевым» путем.
Предугадываю некоторые нападения разъясню:
«Выполнять JS» — да это так, JS можно с эмулировать, но не факт что эмулированный JS выдаст нужные результаты
«Читать базу» — в нашем примере, JS служит лишь для замены и вызова параметров из таблицы, а они у нас генеряться фоном при загрузке, а т.к. их нет не на странице ни в заголовках, то их определить очень проблематично. То что вставка происходит на лету, этого бот отловить не сможет, а если и сможет, то тому мастеру который это сделает, ну просто не нужен будет Ваш форму или блог или еще что по проще, ему по зубам будет система безопасности банк-клиентов :-)
     
                 
  
		
	
 
    
    
0 комментариев