Captcha на Perl
В статье описан метод защиты от автоматического заполнения и отправки формы с сайта путем динамической генерации картинки с кодом и подтверждения правильности ввода. |
Captcha: Как это работает
Когда происходит заполнения полей с данными, система просит пользователя указать код, который он видит на картинке. После проверки правильности ввода происходит решение - пускать клиента в систему или нет. Большой плюс такого метода - надежность. "Вскрыть" картинку и найти в ней цифры не так-то просто, потому что здесь придется писать сложный анализатор изображения.Алгоритм работы Captcha на Perl
- генерируем случайное число с заданным количеством разрядов или слово из словаря (будет использоваться как надпись на картинке) - пароль
- создаем случайный код сессии
- во временном каталоге создаем файл с именем сессии, внутри содержится сгенерированный пароль
- не забываем удалять старые файлы сессий, время жизни которых истекло - неудачные попытки авторизации
- в заполняемой пользователем форме вставляем hidden поле с кодом сессии и поле ввода пароля
- генерируем и показываем на странице подготовленную картинку с паролем (делаем ее трудночитаемой для возможных анализаторов, но понятной человеку)
- после отправки заполненной формы сравниваем содержимое файла сессии с введенным паролем, если значения совпадают - значит форму заполняет человек, вносим данные
- удаляем файл завершившейся сессии
Замечания по реализации
Сначала была мысль не использовать файлы сессий, а передавать в форме в hidden поле зашифрованный по MD5 пароль или обойтись просто созданием временных файлов с именами-значениями пароля, и проверять только их наличие. Но решил все же делать с запасом надежности. Случайный пароль для картинки$kol_digit=5; @pass_chars=(0..9); srand(); $password=join("", @pass_chars[map {rand @pass_chars}(1..$kol_digit)]);Не забываем раскручивать генератор случайных чисел. В примере пароль создается исключительно из цифр, но для повышения безопасности можно добавить и буквы
@pass_chars=("A".."Z", "a".."z", 0..9, qw(% ! $ % ^ & *));Также можно использовать слова и куски текста из словаря.
Шифрованный код сессии
Используется модуль Perl Digest::MD5 (http://search.cpan.org/dist/Digest-MD5/) Уникальная строка для шифрования - текущее время в raw-формате, а также процесс скрипта.$salt=Digest::MD5->new; $hash = $salt->add(time().$$); # шифруем методом ASCII-HEX $session_code=$hash->hexdigest;
Подготовленная картинка с паролем
Картинка отображается на странице как STDOUT работы небольшого скрипта, генерирующего картинку, код сессии передаем скрипту как параметр<img align="right" src="/cgi-bin/anti_robot_img.cgi?code=<session_code>" border=1 alt="">Если параметр не задан - генерируется картинка со случаным паролем. Для создания и вывода картинки используется модуль Image::Magick (http://www.imagemagick.org/) Слово пароля посимвольно выводим на изображение, каждая буква отображается со случайным сдвигом по горизонтали и вертикали, а также вращением. После этого "зашумляем" изображение - сверху в случайных местах разбрасываем разноцветные точки.
Модуль
# введи число, изображенное на картинке # защита от заполнения формы с данными роботами # Vladimir Maximenko [email protected] package anti_robot_img; use Digest::MD5; use Image::Magick; require Exporter; @ISA = qw( Exporter ); @EXPORT = qw( anti_new_session get_pass_str get_pass_img check_anti_robot ); $flag_dir="/tmp"; $time_flag_live=60*60; # генерация пароля $kol_digit=5; @pass_chars=(0..9); #@pass_chars=("A".."Z", "a".."z", 0..9); # возвращаемая картинка $img_width=80; $img_height=30; $noise_pixels=100; # строка случайных символов для картинки sub get_pass_str { srand(); return join("", @pass_chars[map {rand @pass_chars}(1..$kol_digit)]); } # шифрованый код сессии sub enctypt_session_code { my $salt=Digest::MD5->new; # уникальная строка для шифрования my $hash = $salt->add(time().$$); # шифруем методом ASCII-HEX return $hash->hexdigest; } # удаляем старые сессии sub del_old_session { opendir (DIR, $flag_dir); my @flag_files=readdir (DIR); closedir (DIR); shift(@flag_files);shift(@flag_files); foreach $f (@flag_files) { if ($f =~ /\.anti_robot$/) { my $mtime=(stat("$flag_dir/$f"))[9]; if ($mtimeМожно еще добавить вывод букв разными шрифтами и цветами, а также использовать разноцветный фон (например кусочки фотографий)
Владимир Максименко
« Назад