Captcha своими руками

09.05.2011
На любом интернет ресурсе с поддержкой комментариев и вообще любой обратной связи есть проблема спама, бывает стоит отвернуться, как на сайте уже 2000+ спамерских сообщении. Самым распространенным методом защиты является ввод человеком текста изображенного на картинке. Разберём это всё на моём примере.

Первый спам


Изначально на этом сайте стоял [URL="http://www.accross.su/?page=blog&id=14"]виджет комментариев Вконтакте. Но несмотря на все свои плюсы, сделать свою форму с комментариями и сделать её внешний вид как тебе угодно всё таки мне хотелось больше. И в итоге я отказался от этого виджета в пользу своего. Сделал формочку и сразу же подумал, - "Надо бы защиту от спама сделать, хотя бы капчу", но лень и мысль о том что на сайте пока мало посещений сделали своё дело, я оставил всё как есть.
Пока однажды не заметил на сайте 1400+ комментариев со спамом О_О Удалил их все, но они потихоньку всё равно продолжали добавляться. После этого нашёл свой старенький скрипт капчи (вернее сказать нашёл его ещё давно в закромах интернета, но немного изменил под себя), прикрутил и...спам даже и не думал прекращать появляться, тогда я добавил предварительную проверку комментариев, что бы пользователи не видели всего этого мусора. И начал разбираться, почему же бот обходит капчу.

Ошибки в captcha


Первое, о чём я подумал - умный бот распознаёт текст на картинке. Как решение этой проблем, сделал так называемый "шум" на капче, но это не помогло.
Тогда я полез в сам скрипт генерации captcha, и нашёл в нём главную ошибку.
Привожу алгоритм скрипта:
1) Создаём изображение из первообраза (before.png);
2) Генерируем случайное число и записываем его в сессию;
3) Выводим это же число в captcha;
4) Искривляем изображение.
И в итоге имеем вот [URL="http://www.accross.su/data/page/include/captcha.php"]такой рисуночек.
При отправке пользователем комментария, происходит сверка числа записанного в сессию и числа которое ввёл пользователь, в качестве подтверждения. Если они равны, то добавляем комментарий, а если нет, то увы и ах...Главная же ошибка была в том, что пользователь без проблем может посмотреть данные которые хранятся у него в сессии (также как и куки), а для бота это сделать ещё проще. Т.е. ответ на капчу бот находил в сессии.

Исправляем ошибку


Решение я использовал довольно простое, в сессию я записывал число уже немного изменённое, а если конкретно, то отнимал от него 123 и записывал в сессию. Значит при добавлении числа мы теперь будем не только сравнивать числа, но и производим сначала обратную операцию с числом взятым из массива $_SESSION, т.е. прибавляем 123.
После этих манипуляций спам прекратился.
Ещё надёжнее было бы использовать хэш.

Скрипт


Скачать мой скрипт можно [URL="http://www.accross.su/files/captcha.rar"]здесь, там же в архиве находится первообразное изображение с шумами.
Вставляем капчу в сайт вот так:

А при добавлении комментария проверяем числа вот так:
session_name('Captcha');

session_start();
if (($_SESSION['captcha'] + 123) == $_POST['code']))
{
}

Где $_POST['code'] введённые символы пользователем.