The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Реализация теста Тьюринга на Perl (ввод цифр изображенных на картинке) (perl image auth web cgi)


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: perl, image, auth, web, cgi,  (найти похожие документы)
From: Vladimir Maximenko <4raznoe@mail.ru> Newsgroups: email Date: Mon, 12 Jul 2004 18:21:07 +0000 (UTC) Subject: Реализация теста Тьюринга на 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/ Слово пароля посимвольно выводим на изображение, каждая буква отображается со случайным сдвигом по горизонтали и вертикали, а также вращением. После этого "зашумляем" изображение - сверху в случайных местах разбрасываем разноцветные точки. Можно еще добавить вывод букв разными шрифтами и цветами, а также использовать разноцветный фон (например кусочки фотографий) Исходники модуля можно взять по адресу http://voldemar.info/files/anti_robot_img.pm (копия в конце статьи) Система успешно применяется на сайте "ПРАЙСЫ online" в разделе "Доска объявлений" http://www.price-list.kiev.ua/cgi-bin/msg_board.cgi?do=add-msg Владимир Максименко - веб-мастер http://www.price-list.kiev.ua E-Mail: 4raznoe@mail.ru http://WWW.VOLDEMAR.INFO 12.07.2004
# anti_robot_img.pm # введи число, изображенное на картинке # защита от заполнения формы с данными роботами # Vladimir Maximenko 4raznoe@mail.ru 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<time()-$time_flag_live) { unlink("$flag_dir/$f") || die "$!"; } } } } # проверяем, правильно ли введен проверочный код sub check_anti_robot { my ($pass_str, $session_code)=@_; # была такая сессиия ? if (-e "$flag_dir/$session_code.anti_robot") { # правильный пароль ввели ? $check_pass=""; open(FILE,"$flag_dir/$session_code.anti_robot") || die "$!"; while (<FILE>) { $check_pass.=$_; } close(FILE); if ($pass_str eq $check_pass) { return(1); } else { return(0); } } else { return(0); } } # новая сессия, готовим ловушку для робота sub anti_new_session { # новые случайные значения my $new_pass_str=&get_pass_str(); my $new_session_code=&enctypt_session_code(); # удаляем старые сессии &del_old_session(); # пишем в проверочный файл open(FILE,">$flag_dir/$new_session_code.anti_robot") || die "$!"; print FILE $new_pass_str; close(FILE); return $new_pass_str, $new_session_code; } # выводим подготовленную картинку с паролем sub get_pass_img { # из номера сессии достаем пароль if ($_[0] and -e "$flag_dir/$_[0].anti_robot") { $pass_str=""; open(FILE,"$flag_dir/$_[0].anti_robot") || die "$!"; while (<FILE>) { $pass_str.=$_; } close(FILE); } else { $pass_str=&get_pass_str(); } # новая картинка $image = Image::Magick->new; $image->Set(size=>$img_width."x".$img_height); $image->ReadImage('xc:white'); # выводим пароль с искажением текста my $step_x=15; my $base_x=5; my $base_y=$img_height-5; foreach my $letter (split(//, $pass_str)) { # сдвиг и вращение буквы my $sdvig_x=int(rand(4))-2; my $sdvig_y=int(rand(10))-5; my $rotate=int(rand(60))-30; $image->Annotate( antialias => 'true', pointsize => 22, x => $base_x+$sdvig_x, y => $base_y+$sdvig_y, rotate => $rotate, fill => 'black', encoding=> 'windows1251', text => $letter ); $base_x+=$step_x; } # добавляем шум (для затруднения восприятия) for my $i (1..$noise_pixels) { my $rnd_x=int(rand($img_width)); my $rnd_y=int(rand($img_height)); $image->Set("pixel[$rnd_x,$rnd_y]"=>"red"); } # выводим картинку binmode STDOUT; $image->Write('gif:-'); } 1;

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

Обсуждение [ Линейный режим | Показать все | RSS ]
  • 1.1, igor (??), 02:48, 13/07/2004 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    У тебя в урле картинки прямым текстом указано число, которое изображено ... не хорошо
     
     
  • 2.3, scorp21 (??), 11:33, 13/07/2004 [^] [^^] [^^^] [ответить]  
  • +/
    От этого избавиться можно.
    А так в принципе очень даже ничего.
    Немного подшлифовать, заменить gif на png и рабочий package готов.
     

  • 1.2, Tigrisha (?), 09:03, 13/07/2004 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    однако действительно дыра получается. Роботу совершенно незачем анализировать картинку. Проще взять и вынуть число из URL. Ведь они у тебя довольно простого вида
    http://www.price-list.kiev.ua/cgi-bin/anti_robot_img.cgi?code=53191.

    Соответственно кусочек после code и есть число. :)

     
     
  • 2.4, Vladimir Maximenko (?), 11:35, 13/07/2004 [^] [^^] [^^^] [ответить]  
  • +/
    Упс !

    действительно ошибся с кодом сессии
    исходник исправил

    нужно читать так
    Картинка отображается на странице как STDOUT работы небольшого скрипта, генерирующего картинку, код сессии передаем скрипту как параметр
    <img align="right" src="/cgi-bin/anti_robot_img.cgi?code=<session_code>" border=1 alt="">

     

  • 1.5, AcidumIrae (?), 12:45, 13/07/2004 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Perl конечно хороший язык, но PHP рулит
    ----------------------------------------
    header("Content-type: image/png");
    session_start();
    //Config
    $font   = 4;   //Largest built-in font
    $width  = 100; //Image width
    $height = 35;  //Image height
    $num    = 255; //Number of random background lines

    $minc   = 4;   //Minimum word length
    $maxc   = 8;   //Maximum word length

    // seed with microseconds
    function make_seed()
    {
      list($usec, $sec) = explode(' ', microtime());
      return (float) $sec + ((float) $usec * 100000);
    }

    mt_srand(make_seed());

    $len=mt_rand($minc,$maxc);
    $string="";
    for($i=0;$i<$len;$i++)
    {
      if(mt_rand(0,1))
        $c=mt_rand(65,90);
      else
        $c=mt_rand(97,122);
      $string.=chr($c);
    }

    $_SESSION['word_verify']=$string;

    /*********************************************************/
    $im     = imagecreatetruecolor($width,$height);
    $tcolor = imagecolorallocate($im, 0, 0, 0);
    $bcolor = imagecolorallocate($im, 255, 255, 255);

    $fx  = imagefontwidth($font);
    $fy  = imagefontheight($font);

    $x=mt_rand(2,$width-$fx*strlen($string)-2);
    $y=mt_rand(2,$height-$fy-2);

    imagefill($im, 1, 1, $bcolor);
    imagerectangle( $im, 0, 0, $width-1, $height-1, $tcolor);

    //Drawing random lines
    for($i=0;$i<$num;$i++)
    {
      $tx = mt_rand(0,$width);
      $ty = mt_rand(0,$height);

      $dx = mt_rand(mt_rand(-3,0),mt_rand(0,3));
      $dy = mt_rand(mt_rand(-3,0),mt_rand(0,3));

      imageline($im,$tx,$ty,$tx+$dx,$ty+$dy,$tcolor);
    }

    //cleaning box for text
    imagefilledrectangle( $im, $x-1, $y-1, $x+$fx*strlen($string)+1, $y+$fy+1, $tcolor);
    imagefilledrectangle( $im, $x-1, $y-1, $x+$fx*strlen($string)+1, $y+$fy+1, $bcolor);

    //Writing text
    imagestring($im, $font, $x, $y, $string, $tcolor);
    imagestring($im, $font, $x+1, $y, $string, $tcolor);

    imagerectangle( $im, 0, 0, $width-1, $height-1, $tcolor);

    imagepng($im);
    imagedestroy($im);

     
  • 1.6, Questy (??), 13:20, 13/07/2004 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    У меня при заходе на сайт генерятся хитрые code, которые ничего не дадут при анализе.

    Да и зайдя на http://www.price-list.kiev.ua/cgi-bin/anti_robot_img.cgi?code=53191 тоже получил не 53191.

     
  • 1.7, foobar (?), 17:48, 13/07/2004 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Можно и картинки обойти, если очень захотеть ;)
    На /. как-то пробегало, открываем какой-нить порно ресурс и за показ фришного контента требуем от юзеров распознать _вашу_ картинку...
     
  • 1.8, danver (?), 20:37, 14/07/2004 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Скажите, а зачем картинку выводят в PNG ?
     
     
  • 2.9, Astor (?), 02:04, 15/07/2004 [^] [^^] [^^^] [ответить]  
  • +/
    Потому что это стандарт де-факто для опенсурсного ПО. JPEG'и, BMP и прочие GIF'ы не подходят по лицензионным соображениям.
     

  • 1.10, Dr. Nebula (?), 11:55, 13/05/2005 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Хороший модуль, только на мой взгляд несколько сыроват: есть лишние подпрограммы, да и удалять старые файлы сессий лучше не при начале новой (ибо при частом обращении есть шанс, что кто то начнет новую еще до того как будет обработан преведущий запрос), а в подпрограмме проверки - если есть такая сессия, но код неправильный - удалить файл сессии
    И возможно следует объединить в одну подпрограмму создание новой сессии и генерации картинки
    Но это только мое мнение, глубоко модуль не копал, только посмотрел
     
  • 1.11, Dimma (?), 01:31, 30/08/2005 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Тоже по теме можете посмотреть
    http://www.progland.com/protect_forms.htm
     
  • 1.12, СТАС (?), 14:20, 23/12/2005 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Что за шняга дайте готовый скрипт накой нам это ?? выложите сам скрипт как он должен вызывать модуль а то я ламер и и не тока я незнаем как чё делать !
     
     
  • 2.13, Dr. Nebula (?), 23:37, 25/12/2005 [^] [^^] [^^^] [ответить]  
  • +/
    >Что за шняга дайте готовый скрипт накой нам это ?? выложите сам
    >скрипт как он должен вызывать модуль а то я ламер и
    >и не тока я незнаем как чё делать !

    Учиться

     

  • 1.14, Lookfor (?), 14:28, 26/12/2005 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Друзья, помогите ламеру разобраться что к чему.
    Что и куда нужно поместить что-бы это все заработало...
    Есть сервер, на нем стоит Perl, и сайт на котором есть заполняемая форма.
    Что нужно написать в htm файле? И какие куда скрипты поместить? Спасибо!!!
     
  • 1.17, Жан (?), 17:29, 24/05/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Жалко, что на последнее сообшение по установке так никто и не ответил.
     
  • 1.19, Федор (?), 16:55, 17/08/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    да жалко но можно покапаться и найти самому что куда  вставлять, так и сказано выше УЧИТЬ :)
     
  • 1.20, Roman (??), 17:51, 29/08/2006 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    на РНР проще организовать... и в JPEG можно, и в PNG и даже в файл - а потом этот файл читать.
    а зачем сохранять данные в файл? можно ведь сохранять в сессию, а код сессии - в куки пользователю.
     
  • 1.21, Костя (??), 11:43, 23/01/2007 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    У меня неболшая проблемка по работе указанного модуля.
    У меня не получается сходу картинку выводить в форму приходится сохранять на сервере, а src= выводить её местоположение.
    Нельзя как нить выводить в браузер без создания файла?
     
  • 1.22, grey (??), 14:42, 28/02/2007 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Господа... Вешался на Annotate? покопал форумы - нарыл что параметр gravity - обязательный... воткнул, вешацца перестало, но в картинку текст не пихает, выдает только фон и шум.
    Шрифт видит - проверено.
    Куда копать?

    ЗЫЖ: Неплохо бы в статью добавить несколько строк про Контент-тайп, а то ведь у слабодумающих набор символов будет выдавать ;о)

     
  • 1.23, Юзер (??), 13:37, 26/02/2009 [ответить] [﹢﹢﹢] [ · · · ]  
  • +/
    Нужно прописать путь до шрифта font=>'путь.../шрифт.ttf'
     

    игнорирование участников | лог модерирования

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Спонсоры:
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2020 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру