|
Все для программиста! |
| ||||||||||||||||||||||||||||||||
|
CodeNet / Языки программирования / PHP / Cookies и сессии
CodeNet / Языки программирования / PHP / HTML, формы CodeNet / Языки программирования / PHP / Безопасность Защита Web-форм от автоматической обработки© Mike, 10.10.2004
Статья описывает способ реализации механизма, позволяющего бороться с автоматическим заполнением форм, ложными регистрациями и спамом через форму обратной связи. Требования: PHP>=4.0.6, GD >=2.0. Исходные тексты можно скачать тут. Данная статья написана по мотивам статьи Nathan Rohler "Security Images in PHP" опубликованной на сайте #Dev Shed 9 августа 2004 года. Вообще, с начала, меня посетила мысль ее перевода, но, во первых автор выбрал интересный, но не самый тривиальный вариант решения проблемы, а во вторых, мне бы вряд ли удалость сформулировать на русском языке такое обилие мыслей. Последнее время, в связи с распространяющейся эпидемией спама, веб-мастера, стали все чаще и чаще прятать адреса своей электронной почты (E-Mail). Многие стали использовать формы обратной связи. Но как оказалось, такую защиту можно обойти. И уже на сегодняшний день, существует огромное количество программ, предназначенных для рассылки спама, через формы обратной связи. Наша задача - сделать так, чтобы сообщение вам смог отправить только "живой человек". Чаще всего, для этого используют небольшие картинки, на которых выводится текст. Пользователя просят продублировать этот текст в поле ввода. Если дублирование производится неверно, то форма не обрабатывается. На сегодняшний день мне не знакомо ни одной программы, способной обойти такую защиту. Я даже на знаю ни одной программы, вообще, хоть как-то пытающуюся распознать содержимое картинки. По этому, можно смело сказать, что сегодня нет необходимости как-то искажать изображение на картинке. Но мы смотрим в будущее. Генерация изображенияАвтор предложил следующий алгоритм: сложное изображение на картинке формируется с помощью заранее подготовленных подложек. После чего на подложки выводится текст, случайным шрифтом, случайного размер и, естественно, случайного содержания. Основной недостаток такого алгоритма заключается в том, что существующую "подложку" можно быстро вычислить. А после этого вычесть из изображения, которое необходимо распознать и таким образом получить картинку с чистым текстом. А для распознания такого текста уже сегодня существует масса программ. Наша задача - сделать абсолютно случайную подложку, с текстом, который не то что распознать сложно, его прочитать тяжело. Я бы предложил следующий алгоритм:
Увеличивать и уменьшать изображение необходимо с использованием сглаживания, иначе даже человек не сможет прочитать текста. Если вам кажется, что рисовать фрактал слишком сложно, то можно нарисовать простую сетку. Принцип работы механизмаПри заходе пользователя на страницу с формой, мы создаем сессию и записываем в зарегистрированную переменную случайный код:
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);
?>
Вроде все. Если что-то, оставляйте комментарии. Комментарии пользователей (всего 26)vitalvarna / 19 ноября 2008, 09:22:09У меня такая проблема: файл - обработчик у меня другой, не index.php, все работает отлично, но если пользователь не правильно ввел цифры, после нажатия кнопки НАЗАД(имею ввиду из файла обработчика), пользователь возвращается на страницу, где находится форма обратной связи, а эта форма уже пуста! Пользователю надо опять набирать свой эмаил, текст сообщения и т.д. И как поставить кнопку для обновления кода, без обновления страницы и формы? Lloid69 / 29 марта 2008, 14:26:17Мой вариант: grem11n / 29 августа 2007, 17:41:22одна из немногих статей в нете помагающая. Спасибо автору Robinnovich / 16 июня 2007, 20:53:04чето у меня вобще непхпло немного переделал ) tar / 05 февраля 2007, 20:00:11Почему только в IE и при загрузке из фрейма не отображаются tar / 05 февраля 2007, 19:58:59Почему только в IE и при загрузке из фрейма не отображаются цифры RussianSpy / 29 ноября 2006, 11:58:02Интересно... А что же будет с теми у кого отключены куки? Получается что они не смогут работать с подобной схемой. Не стоит делать защитную картинку работа которой основана на сессиях. Да и вообще код как-то великоват - класс который я сам написал работает без сессий и там раз в 5 меньше кода... Style)r / 09 октября 2006, 22:49:26
mike / 08 сентября 2006, 11:07:44Основная идея - не менять картинку для одного пользователя в момент обновления. Менять только в момент добавления. Цитата: Это бред чистой воды :) От замены микрсекунд на секунды ничего не поменяется. Просто внутри одной секунды генератор случайных чисел будет инициализироваться одинаково. Style)r / 07 сентября 2006, 18:28:12Я заради вас навіть зареєструвався тут))) Отображены только последние 10 комментариев. Читать все комментарии >> |