Почтовые сервисы, кажется, подустали от автоматических регистраторов в мгновение ока сметающих "красивые" логины и использующих авторегистрацию для рассылки спамовых писем.
В последнее время появилась мода на регистрацию при помощи "магических чисел" нанесенных на картинку. Если вы не знаете о чем речь, попробуйте, например, зарегистировать e-mail на
Chat.RU. Идея проста - на картинку наносится число, которое человек при регистрации должен "вбить" в текстовую форму, считается, что человеку это особых неудобств не приносит, а вот регистрационные скрипты с этим ничего сделать не могут.
Число каждый раз меняется и генерируется как можно более хитрым способом, что бы вычислить его, например, через параметры, передаваемые скрипту, рисующему картинку, было достаточно трудно.
Тот же Chat.RU, для примера, каждые несколько часов генерирует набор пятизначных цифр, хеширует их через MD5 и помещает все соответствия в базу данных. Этот хеш является параметром для скрипта, генерирующего картинку.
Способ достаточно странный и трудоемкий, но "кул хацкеров" все же отпугивает. Странный потому что совершенно непонятно для чего оставлять хоть какое-то, пусть непрямое, соотвествие между номером на картинке и параметром используемым для его генерации - перебор на Perl с восстановлением числа на Pentium III-866 занимает, в среднем, примерно 30 секунд. Если не повезет - все 70. Я пробовал.
Вообще результат не такой уж плохой, но мне захотелось его улучшить. Не то что бы я занимаюсь спамом или регистрацией логинов, просто было интересно решить эту задачу. Отвергнув способ с улучшением способа нахождения обратного по хешу, как трудно поддающийся улучшению я решил сконцентировать силы на распознавании самой картинки.

Забегая вперед, скажу, что концентироваться пришлось недолго. Сначала я обратил внимания на то, что выдаваемая пользователю картинка имеет формат PNG, значит новая
GD-библиотека, вкомпиленная в
PHP на моей машине, вполне сможет с ней работать. Поэтому первое что я сделал - прошелся по всей картинке и, двумя циклами, перевел ее в ASCII - графику, чтобы лучше рассмотреть, а заодно убедиться, что GD картинку "понимает".
Моя задача очень упростилась - как оказалось все цифры в строке одинакового размера, а координаты начала печати от картинки к картинке не изменяются ни на пиксел.
Сверять цифры с заранее заготовленными образцами было слишком просто и грустно, так что я решил просто суммировать количество пикселей, составляющих цифру, в каждом столбце одного знака и сравнивать получившееся значение с просчитанным заранее. Как оказалось для этой задачи необходимы только первые три столбца каждой цифры. Получилась такая вот программка на PHP, которая позволяет регистрировать e-mailы на Chat.RU в любом количестве.
<?
function OCRNum($URL)
{
$out = '';
$nums = array (464,23,245,242,233,674,685,343,377,266);
$png = imagecreatefrompng ($URL);
for ($x = 10; $x<54; $x++)
{
$sums = array(0,0,0);
for ($i = 0; $i<3; $i++)
for ($y = 10; $y<20; $y++)
$sums[$i]+= imagecolorat ($png, $x+$i,$y);
$x+=8;
$out.= array_search((int)join('',$sums), $nums);
};
return $out;
};
function GetCryptKey()
{
$fp = fopen ("http://chat.ru/user/register.html?", 'r');
while (!feof ($fp))
{
$line = strstr($line = fgets($fp, 1024), 'personal_key_crypt=');
if ($line!==false) break;
};
fclose ($fp);
if (ereg ("[[:alnum:]_]+=([^\">]+)", $line, $regs))
return $regs[1]; else return false;
};
function RegProc($crypt_key)
{
global $user, $pass;
$key = OCRNum("http://chat.ru/user/image_gen.html?".
"personal_key_crypt=$crypt_key");
$URL = "http://chat.ru/user/register.html?personal_key=$key&".
"personal_key_crypt=$crypt_key&username=$user&pw1=$pass&pw2=$pass&".
"action=Register/Зарегистрировать";
$fp = fopen ($URL, 'r');
while (!feof($fp))
{
$line = fgets ($fp, 2048);
if (strstr ($line, '<head>'))
echo "$line\n<BASE HREF=http://www.chat.ru>\n"; else
echo $line;
};
fclose ($fp);
};
if ($user=='' || $pass=='')
echo <<<HTML
<STYLE>
body, td, input {font-family: Trebuchet MS; font-size: 15px}
</STYLE>
<BODY BGCOLOR=WHITE TEXT=BLACK>
<TABLE WIDTH=300>
<FORM ACTION=$PHP_SELF>
<TR><TD>User name:</TD><TD><INPUT TYPE=TEXT NAME=user></TD></TR>
<TR><TD>Password:</TD><TD><INPUT TYPE=TEXT NAME=pass></TD></TR>
<TR ALIGN=CENTER><TD COLSPAN=2><INPUT TYPE=SUBMIT VALUE=Register>
</TD></TR>
</TABLE>
</FORM>
HTML;
else
{
$ckey = GetCryptKey();
if ($ckey === false) echo 'Не могу зарегистрировать.'; else
RegProc ($ckey);
};
?>
|
Берите, пользуйтесь, пока ребята из Chat.RU не сменили алгоритм. :) Вообще Chat.RU - сервис довольно странный и дырявый, но об этом как-нибудь в другой раз.