Капча (CAPTCHA) своими руками

Воскресенье, 06.01.08 10:35 мск
Формы — один из важнейших элементов Web-страниц. Их предназначение — организации взаимодействия сайта с пользователем.
Передача информацию через формы от пользователей, которые путешествуют по
нашему сайту, — общая практика, притом, независимо от того, насколько проста или сложна операция, с помощью которой эта процесс осуществляется.
К сожалению, спам принес с собой целую серию проблем, связанных с автоматическим введением данных через формы на интернет-сайтах: существуют боты (скрипты, созданные специально, чтобы сымитировать поведение живого человека для осуществления определенных целей), сканирующие сеть в поисках форм, посредством которых они рассылают огромное количество нежелательных сообщений.
Появились удачные решения, которые могут быть использованы, чтобы запретить (или где не возможно, серьезно помешать) этим ботам, для того, чтобы они не смогли рассылать нам нежелательные данные. Одно из таких решений, которое наиболее часто используется, названо CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) и предназначено для добавки в формы случайно-сгенерированного изображения, содержащего текст с искривленными символами.
Содержание этого изображения должно быть введено в специальное поле, и должно пройти проверку на сервере: в случае, если строка не оказалась правильной, данные формы не отправляются и, ввод данных запрашивается повторно.
В этой небольшой статье мы увидим, как можно написать простой скрипт, который позволит нам избежать того, чтобы боты посылали нежелательные данные нашему серверу. Очевидно цель, которая мы ставим для себя, чисто дидактическая, и для серьезного (профессионального) программирования я советую изучить соответствующие решения (в зависимости от того, где это будет применяться). Итак, начнём!
Генерация случайного изображения
Первая проблема, которую нужно решить - это найти способ генерации случайных изображений. Они должны быть в то же время понятными для пользователя, но непонятными для ботов, которые анализируют наши формы.
Генерация случайного изображения обычно основывается на использовании картинки фона с разнородными цветами, на котором нарисована строка проверки.
К тому же картинка часто засорена линиями и случайными точками, чтобы осложнить использование edge detection (фильтр, который, вместе с другими, часто используют, чтобы извлечь строку из картинок автоматическим способом), и используемый шрифт повернут и искажен.
Очевидно, что в данной ситуации изображение должно быть довольно сложным, чтобы не быть распознанным автоматической программой, но быть довольно простым для того, чтобы быть понятным для человека.
Скрипт, который мы напишем, не использует cookie или сессии. Сделано это для того, чтобы защитить информацию от перехвата данных ботом. Скрипт основывается на взаимодейтсвии между скриптом, который генерирует изображение и скриптом, который генерирует форму. На практике страница, которая делает форму видимой, генерирует случайную строку. Строка будет сохранена в базе данных, и ей (строке) будет соответствовать случайный однозначный ключ.
Этот ключ будет читаться из скрипта как параметр генерируемой картинки, который запишет в базу данных строку. Ключ перейдет в скрытое поле (hidden) к странице назначения, которая и займется осуществления проверки. Этот ключ можно будет использовать один единственный раз, независимо от того, был ли он введен правильно или нет.
Первая операция, состоит в следующем, — мы создадим таблицу, которую будем дальше использовать:
CREATE TABLE validation (
   id INT UNSIGNED NOT NULL AUTO_INCREMENT,
   url_key CHAR(40) UNIQUE NOT NULL,
   captcha CHAR(32) NOT NULL,
   expire_date DATETIME NOT NULL,
   PRIMARY KEY(id),
   INDEX(url_key)
);

Поле url_key будет содержать ключ (произведен случайно и зашифрован, используя алгоритм SHA1), поле captcha — строка проверки, и expire_date — будет датой, по истечении которой, ключ автоматически станет истекшим и, таким образом, не сможет быть использован больше.
Теперь мы можем поступить к написанию скрипта для генерации изображения. Процесс может быть более или менее сложным. Я ограничусь тем, что покажу очень простой пример, который использует текстуру фона, на которой будет произведена строка, использующая один из шрифтов, поставляемых с библиотекой GD.
Я думаю, что вполне очевидно, что скрипт довольно прост и приведен здесь только как пример, чтобы позволить правильное функционирование программы.
<?php
$pdo 
= new PDO('mysql:host=localhost;dbname=captcha'
'root''');
$stmt $pdo->prepare("SELECT * FROM validation WHERE 
url_key = ? AND expire_date > NOW()"
);
$stmt->execute(array($_GET['token']));
$row $stmt->fetch(PDO::FETCH_ASSOC);
$texture imagecreatefrompng('texture.png');
$source imagecolorat($texturerand(0imagesx($texture)), 
rand(0imagesy($texture)));
$r = ($source >> 16 0xff) + 50;
$g = ($source >> 0xff) + 50;
$b = ($source 0xff) + 50;
$text_color imagecolorallocate($texture$r$g$b);
imagestring($texture5, (imagesx($texture) - 
strlen($row['captcha']) * 5)/ 25,  $row['captcha'],
$text_color);
header('Content-Type: image/png');
imagepng($texture);
imagedestroy($texture);
?>

Важно отметить, что строка, которой предстоит стать видимой, восстановлена из базы данных, и что ключ, переданный GET, не должен быть уже просроченным.
Теперь мы напишем скрипт, который займется генерацией формы и его проверкой:
<?php
function random_string($len)
{
   
$string "";
   
$chars = array("a""b""c""d""e""f""g""h",
   
"i""j""k""l""m""n""o""p""q""r""s"
   
"t","u""v""w""x""y""z""A""B""C""D"
   
"E""F""G""H""I""J""K""L""M""N""O"
   
"P""Q""R""S""T""U""V""W""X""Y""Z"
   
"0""1""2""3""4""5""6""7""8""9");
   for(
$i 0$i $len; ++$i)
   {
      
shuffle($chars);
      
$string .= $chars[0];
   }
   return 
$string;
}
$message 'введите следующий текст 
для проверки:'
;
$pdo = new PDO('mysql:host=localhost;
dbname=captcha'
'root''');
$pdo->setAttribute(PDO::ATTR_ERRMODE
PDO::ERRMODE_EXCEPTION);
if(isset(
$_POST['validate_token']))
{
$stmt $pdo->prepare("SELECT * FROM validation 
WHERE url_key = ? AND expire_date > NOW()"
);
$stmt->execute(array($_POST['token']));
$row $stmt->fetch(PDO::FETCH_ASSOC);
$message = ($row && ($row['captcha'] == 
$_POST['validate_token'])) ? 'token corretto' 
'token <strong>NON</strong> corretto';
   
$stmt $pdo->prepare("DELETE FROM validation 
WHERE url_key = ?"
);
   
$stmt->execute(array($_POST['token']));
}
$pdo->query("DELETE FROM validation WHERE 
expire_date <= NOW()"
);
$url_key sha1(uniqid(rand(), true)); 
$captcha random_string(6);
$stmt $pdo->prepare("INSERT INTO validation 
(id, url_key, captcha, expire_date) VALUES 
('', ?, ?, DATE_ADD(NOW(), INTERVAL 5 MINUTE))"
);
$stmt->execute(array($url_key$captcha));
?>
<html>
  <head>
      <title>CAPTCHA test</title>
   </head>
   <body>
      <form method="POST" 
       action="<?php echo $_SERVER['PHP_SELF']; ?>">
         <input type="hidden" name="token" 
         value="<?php echo $url_key?>" />         
         <?php echo $message?>         </p>         <img src="captcha.php?token=
         <?php echo $url_key?>" width="200" 
         height="30" />
         <br/>
         <input type="text" name="validate_token" />
         <input type="submit" name="action" value="Test" />
      </form>   </body>
</html>

Проанализировав скрипт, мы можем выделить различные аспекты:
Функция random_string, используемая для генерации случайного текста, делает строку “неповторимой”, что снижает вероятность повторного использования этой строки.
Каждый раз, когда страница становится видимой (вам еще не посланы данные в POST) мы занимаемся опустошения таблицы, удаляя просроченные записи, и последовательно записываем ключ и строку контроля. Оба скрипта вполне справляются с этим, используя очень простые системы, которые вполне можно улучшить, чтобы повысить надежность.
В форме подтверждения осуществлен истинный и собственный контроль введенных данных, когда простой используется простой SQL-запрос.
И вот, следуя этим простым шагам, мы практически закончили скрипт, получли результат, с минимальным усилием.
Я надеюсь на то, что эта статья смогла помочь вам получить информацию, которая составляет большую часть справочников, которые находятся в сети. Я постарался избежать использования сессий и cookie. Это позволило сделать скрипт совместимым с настройками браузера.
Прежде, чем закончить, я хочу напомнить, что следует обратить внимание на существенный недостаток подобных систем. Сгенерированные изображения, которые используют эту технику, порой плохо различимы людьми, с более или менее плохим зрением.
Чтобы избежать возможных проблем, хорошим тоном будет использование в CAPTCHA того же самого языка, для генерации ключа на языке того, кто должен ввести данные. Это замечание не так уж и усложнит скрипт; оно будет проанализировано в другой статье.

Источник: HTML.IT
Локализация статьи: Kadetoff

Комментарии к статье «Капча (CAPTCHA) своими руками»

1 Den » 17.05.2009 в 21.47
Капча давно перестала быть спасением, придумывайте другие способы спасения от ботов.
2 Risen » 27.08.2009 в 16.08
Сложноватая капча, лучше без подключения к базе данных.
Можно делать каптчу с символами кириллицы.
Kadetoff:
Есть еще такой вариант: без базы данных.
3 Kadetoff » 27.08.2009 в 17.00
Безусловно, не лучший вариант.
Есть несколько неплохих классов (кстати, без подключения к БД), которые использую в работе.
4 ttdionisiy » 22.04.2012 в 19.38
С Праздником Пасхи! wld2w5
На хороший ремонт - хорошие скидки в апреле!!!
Православные мастера собирают заказы!!!
5 kuhnitymnartialt » 3.05.2012 в 06.55
который я уже неделю исчу
6 ирина » 4.05.2012 в 10.30
89879605227 помогите разблокировать

Добавьте свой комментарий:

Имя
Mail
Сайт (если есть)
1+9=

 
Вы можете использовать следующие BB-коды:

[b][/b] - жирный текст
[em][/em] - выделенный текст