PDA

Просмотр полной версии : Проверка значений форм в PHP



NoXX
05.11.2006, 12:00
Обращаюсь ко всем опытным программерам на PHP.
Возник такой вопрос: как сделать так, чтобы скрипт проверял точность введенного значения в форме с значением в картинке, которая генерируется gd (png).
Приведу простой пример:
На сайте отправки СМС-ок с сайта, допустим, UMC (www.umc.ua/sendsms.php), чтобы отправить СМС-ку надо ввести проверочный код, который указан в картинке. Так как сделать, чтоб PHP генерировал картинку со случайным кодом и мог проверять сходность введенного значения и значения в картинке?
Если непонятно, еще один простой пример - http://forum.od.ua/register.php - тоже надо вводить проверочный код для подтверждения регистрации.
В мануале по этому поводу ничего не написано (обыскал его весь).
В имеющихся учебниках тоже ничего дельного не набрел.

Vic87
05.11.2006, 14:42
Защита Web-форм от автоматической обработки

© Mike, 10.10.2004

Статья описывает способ реализации механизма, позволяющего бороться с автоматическим заполнением форм, ложными регистрациями и спамом через форму обратной связи.

Требования: PHP>=4.0.6, GD >=2.0.

Данная статья написана по мотивам статьи 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),r and(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);
?>

dron007
05.11.2006, 14:50
Тут еще можно почитать и найти примеры скрипта: http://www.captcha.ru/
Готовое решение тут: http://www.captcha.ru/kcaptcha.zip
Проверял, работает. Только я бы изменения цвета отключил. Боту пофиг, а человека иногда напрягает.

А приведенный выше пример без изменений использовать нельзя. Во-первых, он генерирует мелкую плохочитаемую картинку. Это неправильно, картинка должна легко читаться человеком, иначе люди просто будут уходить со странички. А во-вторых его вполне реально сломать методами, описанными на указанном сайте.

Так что рекомендую именно Captcha. Автоматическое распознавание текста, расположенного по волнистой линии со всякими искажениями на порядки сложнее а может и вообще невозможно.

iFog
06.11.2006, 18:43
Боту пофиг, а человека иногда напрягает.

Боту не пофиг. И чем плавнее переходы цвета, чем ближе интенсивность цвета букв к интенсивносит фона, чем больше шума на картинке - тем сложнее боту.

Грубо говоря - когда тебе легче читать, то и боту легче. И наоборот.

dron007
06.11.2006, 22:39
Не, я про этот конкретный алгоритм пишу. Там не генерируется специального шума, просто текст по-разному деформируется. И сами буквы разукрашиваются по-разному. Для бота это все просто числа, однозначно отличающиеся от фона, а человеку слабый контраст тяжелее распознавать.

Но там не проблема задать другой цвет букв в конфиге. Случайный просто для примера дан.

iFog
06.11.2006, 23:41
dron007, мне кажется, ты мало интересовался этим вопросом :)

dron007
07.11.2006, 23:06
dron007, мне кажется, ты мало интересовался этим вопросом :)
Если есть конкретные возражения, можно пообсуждать, а просто делать какие-то утверждения - не совсем корректно. Интересовался достаточно, чтобы точно представлять как все это работает. И написать бота для распознавания картинок теми методами, о которых пишется на http://www.captcha.ru/ вполне в состоянии.

Думаю, с утверждением, что буквы цвета #FEFEFE на белом фоне человек вряд ли прочитает, а бот вполне сможет выделить, все согласятся? Так о чем тогда спор?

На этом форуме кстати вполне надежная система защиты от ботов. Правда изредка генерируются трудночитаемые символы. Я бы порекомендовал использовать другой шрифт.
Например, на этой картинке 3-й символ M или H? Когда привыкнешь к шрифту, то понятно, что M, но человек, впервые зашедший, может и H ввести.

NoXX
08.11.2006, 19:11
Если есть конкретные возражения, можно пообсуждать, а просто делать какие-то утверждения - не совсем корректно. Интересовался достаточно, чтобы точно представлять как все это работает. И написать бота для распознавания картинок теми методами, о которых пишется на http://www.captcha.ru/ вполне в состоянии.

Думаю, с утверждением, что буквы цвета #FEFEFE на белом фоне человек вряд ли прочитает, а бот вполне сможет выделить, все согласятся? Так о чем тогда спор?

На этом форуме кстати вполне надежная система защиты от ботов. Правда изредка генерируются трудночитаемые символы. Я бы порекомендовал использовать другой шрифт.
Например, на этой картинке 3-й символ M или H? Когда привыкнешь к шрифту, то понятно, что M, но человек, впервые зашедший, может и H ввести.
Я как раз по этой причине где-то раз 5 пытался зарегиться на этом форуме... код постоянно не совпадал...

NoXX
09.11.2006, 19:52
Спасибо всем за внимание! Я уже сам разобрался как сделать данные процедуры намного проще и посему закрываю топик.