Дадим отпор грубой силе!
Докучаев Дмитрий aka Forb
Xakep, номер #059, стр. 059-062-3
Все, теперь нам осталось только вывести картинку на экран. Для этого переводим поток STDOUT в бинарный режим (ведь наша картинка бинарная) при помощи команды binmode. Далее сообщаем браузеру, что у нас идет тип данных "image/jpeg", и выводим саму картинку методом jpeg:
binmode STDOUT;
print "Content-type: image/jpeg\n\n";
print $image->jpeg;
Сохраняй полученный результат и бегом открывай браузер, чтобы посмотреть на результат. На экране у тебя появится черный квадрат с числом 1000. Поздравляю, ты только что научился выводить динамические картинки! :)
Защита своего проекта
С теорией закончили. Теперь поговорим об организации защиты. Во-первых, каждый раз нам необходимо выводить рандомные значения, а не статическое 1000. Для этого воспользуемся функцией rand. Но rand выдает число с плавающей запятой, поэтому мы его округлим до целого значения функцией int. Вот что у нас получится:
$number = int rand 31337;
Этой командой мы будем генерить целое рандомное значение от 0 до 31337 (не включительно).
Теперь нам надо связать картинку с HTML-формой. Главное - не вздумай делать hidden поле с номером на картинке. Хакер не дурак и быстренько напишет парсер, вытаскивающий этой значение из формы. Разумнее будет создавать для каждой сессии свой MD5-код и помещать его в hidden. И чтобы скрипт понимал передаваемый ему код, надо записать этот самый код в файл и уже затем производить его сравнение с введенной цифрой.
Конечно, сгенерировать MD5 можно и консольной командой "md5 -s строка", но разумнее будет использовать модуль Perl под названием Digest::MD5. Вот как выглядит простенький скрипт, генерящий хеш по строке "time().$$" (текущее время в raw-формате, а также процесс скрипта). После создания уникального номера записываем его файл.
Таблица: Создание хеша сессии
#!/usr/bin/perl
use Digest::MD5;
# Каталог, который не будет виден через web
$chrootdir="/home/user/nonwebbrowseabledir/";
# Новый метод для MD5
$salt=Digest::MD5->new;
# Уникальная строка, по которой ведется шифрование
$string=time().$$;
# Формируем хеш
$hash = $salt->add($string);
# Шифруем методом ASCII-HEX
$id=$hash->hexdigest;
# Открываем файл для записи
open(FILE,">$chrootdir$id") ||
die "Can't open file for write: $!\n";
# Выводим заранее сгенерированный номер
print FILE $number;
close(FILE);
# Выводим контент документа
print "Content-type: text/html\n\n";
# Произвольные данные для формы
print "<HTML><FORM>.....\n";
# Заносим id в форму для последующей проверки
print "<input type=hidden name=hash value=$id>";
После того как юзер передаст все данные скрипту, тебе необходимо будет проверить логин с паролем, а также чекнуть верность введенного номера на картинке. Я сделал это так: открыл файл "$chrootdir$id" ($id пришло сценарию в качестве параметра), извлек из документа номер и сравнил его со вторым параметром формы.
После решения о допуске клиента в систему надо удалить наш вспомогательный файл, иначе у тебя в каталоге будет куча ненужного мусора.