Данная статья написана по мотивам статьи Nathan Rohler "Security Images in PHP" опубликованной на сайте #Dev Shed 9 августа 2004 года. Вообще, с начала, меня посетила мысль ее перевода, но, во первых автор выбрал интересный, но не самый тривиальный вариант решения проблемы, а во вторых, мне бы вряд ли удалость сформулировать на русском языке такое обилие мыслей.
Последнее время, в связи с распространяющейся эпидемией спама, веб-мастера, стали все чаще и чаще прятать адреса своей электронной почты (E-Mail). Многие стали использовать формы обратной связи. Но как оказалось, такую защиту можно обойти. И уже на сегодняшний день, существует огромное количество программ, предназначенных для рассылки спама, через формы обратной связи.
Наша задача - сделать так, чтобы сообщение вам смог отправить только "живой человек". Чаще всего, для этого используют небольшие картинки, на которых выводится текст. Пользователя просят продублировать этот текст в поле ввода. Если дублирование производится неверно, то форма не обрабатывается.
На сегодняшний день мне не знакомо ни одной программы, способной обойти такую защиту. Я даже на знаю ни одной программы, вообще, хоть как-то пытающуюся распознать содержимое картинки. По этому, можно смело сказать, что сегодня нет необходимости как-то искажать изображение на картинке. Но мы смотрим в будущее.
Генерация изображения Автор предложил следующий алгоритм: сложное изображение на картинке формируется с помощью заранее подготовленных подложек. После чего на подложки выводится текст, случайным шрифтом, случайного размер и, естественно, случайного содержания.
Основной недостаток такого алгоритма заключается в том, что существующую "подложку" можно быстро вычислить. А после этого вычесть из изображения, которое необходимо распознать и таким образом получить картинку с чистым текстом. А для распознания такого текста уже сегодня существует масса программ.
Наша задача - сделать абсолютно случайную подложку, с текстом, который не то что распознать сложно, его прочитать тяжело.
Я бы предложил следующий алгоритм:
1. Создаем подложку (для этого можно использовать алгоритм построения фракталов) 2. Добавляем помехи - несколько случайных линий, цвета основного текста. 3. Выводим основной текст 4. Самое интересное - увеличиваем изображение в неровное количество раз - например, в 1.7, в 1.6 5. Уменьшаем изображение до оригинальных размеров
Увеличивать и уменьшать изображение необходимо с использованием сглаживания, иначе даже человек не сможет прочитать текста.
Если вам кажется, что рисовать фрактал слишком сложно, то можно нарисовать простую сетку. Принцип работы механизма
При заходе пользователя на страницу с формой, мы создаем сессию и записываем в зарегистрированную переменную случайный код:
session_start(); session_register("secret_number");
if (intval($_SESSION["secret_number"])<1000) { srand(doubleval(microtime())); $_SESSION["secret_number"]=rand(1000,9999); }
После того как случайный текст сгенерирован, необходимо вывести форму:
<form action="index.php" method="post"> Ваш E-Mail:<br> <input type="text" name="email" value=""><br> <br> Введите код, который вы видите на картинке:<br> <input type="text" name="secretcode" value=""><br> <img src='code.php?=doubleval(microtime());?>' width=101 height=26 vspace=5> <br><br> <input type="submit"> </form>
Скрипт, обрабатывающий данные, отправленные при помощи формы, должен работать примерно следующим образом:
session_start(); session_register("secret_number");
if ($_SERVER["REQUEST_METHOD"]=="POST") {
$error=0; if ($_POST["secretcode"]!=$_SESSION["secret_number"] || intval($_POST["secretcode"])==0) $error=1;
if ($error==0) { $_SESSION["secret_number"]=rand(1000,9999);
// Выполняем необходимые действия с данными // .. print "Hello ".htmlspecialchars(StripSlashes($_POST["email"])); exit; }
if ($error==1) print "<font color=red>Число с картинки введено неверно</font>"; }
// Выводим форму повторно // ...
Генерация изображения
// Регистрируем переменную session_start(); session_register("secret_number");
function mt() { list($usec, $sec) = explode(' ', microtime()); return (float) $sec + ((float) $usec * 100000); }
header("Content-type: image/png");
// создаем изображение $im=imagecreate(101, 26);
// Выделяем цвет фона (белый) $w=imagecolorallocate($im, 255, 255, 255); // Выделяем цвет для фона (светло-серый) $g1=imagecolorallocate($im, 192, 192, 192);
// Выделяем цвет для более темных помех (темно-серый) $g2=imagecolorallocate($im, 64,64,64);
// Выделяем четыре случайных темных цвета для символов $cl1=imagecolorallocate($im,rand(0,128),rand(0,128),rand(0,128)); $cl2=imagecolorallocate($im,rand(0,128),rand(0,128),rand(0,128)); $cl3=imagecolorallocate($im,rand(0,128),rand(0,128),rand(0,128)); $cl4=imagecolorallocate($im,rand(0,128),rand(0,128),rand(0,128));
// Рисуем сетку for ($i=0;$i<=100;$i+=5) imageline($im,$i,0,$i,25,$g1); for ($i=0;$i<=25;$i+=5) imageline($im,0,$i,100,$i,$g1);
// Выводим каждую цифру по отдельности, немного смещая случайным образом imagestring($im, 5, 0+rand(0,10), 5+rand(-5,5), substr($_SESSION["secret_number"],0,1), $cl1); imagestring($im, 5, 25+rand(-10,10), 5+rand(-5,5), substr($_SESSION["secret_number"],1,1), $cl2); imagestring($im, 5, 50+rand(-10,10), 5+rand(-5,5), substr($_SESSION["secret_number"],2,1), $cl3); imagestring($im, 5, 75+rand(-10,10), 5+rand(-5,5), substr($_SESSION["secret_number"],3,1), $cl4);
// Выводим пару случайных линий тесного цвета, прямо поверх символов. // Для увеличения количества линий можно увеличить, // изменив число выделенное красным цветом for ($i=0;$i<8;$i++) imageline($im,rand(0,100),rand(0,25),rand(0,100),rand(0,25),$g2);
// Коэффициент увеличения/уменьшения картинки $k=1.7;
// Создаем новое изображение, увеличенного размера $im1=imagecreatetruecolor(101*$k,26*$k);
// Копируем изображение с изменением размеров в большую сторону imagecopyresized($im1, $im, 0, 0, 0, 0, 101*$k, 26*$k, 101, 26);
// Создаем новое изображение, нормального размера $im2=imagecreatetruecolor(101,26);
// Копируем изображение с изменением размеров в меньшую сторону imagecopyresampled($im2, $im1, 0, 0, 0, 0, 101, 26, 101*$k, 26*$k);
// Генерируем изображение imagepng($im2);
// Освобождаем память imagedestroy($im2); imagedestroy($im1); imagedestroy($im); ?>
|