C, PHP, VB, .NET

Дневникът на Филип Петров


* Добавяне на captcha към автентикационната форма

Публикувано на 05 април 2015 в раздел ОСУП.

В тази статия ще покажем съвсем елементарна форма за captcha. Първо ще започнем с файл „captcha.php“, в който се прави следното:

  • Генерира произволен текст от 8 символа и ги записва в сесията;
  • Генерира картинка от тип PNG с този текст и я изпраща на потребителя.

captcha.php:

<?php
session_start();
// Уверяваме се, че браузъра на клиента не е кеширал картинката
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
// И указваме с хедър, че ще му изпратим картинка
header('Content-type: image/png');

// Генерираме произволен текстови низ и го записваме в сесията
$randomString = base64_encode(openssl_random_pseudo_bytes(6));
$_SESSION['captcha'] = $randomString;

// Избираме си произволен шрифт от директория fonts
$files = glob('./fonts/*.ttf');
$file = array_rand($files);
$font = $files[$file];

// Създаваме картинка с размери 200x60 px
$image = imagecreatetruecolor(200, 60);
// Цвят за шрифта
$black = imagecolorallocate($image, 0, 0, 0);
// Цвят за фона на правоъгълника (може и без него)
$white = imagecolorallocate($image, 255, 255, 255);
// Запълваме правоъгълник
imagefilledrectangle($image,0,0,200,60,$white);
// Добяваме всяка буква поотделно
for($i=0; $i<strlen($randomString); $i++){
 // Картинка, големина на шрифта, ъгъл, отстояние от ляво-надясно,
 // отстояние от горе-надолу, цвят, шрифт и самия текст, 
 // който се добавя (при нас е буква)
 imagettftext ($image, rand(16,22), rand(-30, 30), 11+22*$i, rand(25,58), $black, 
                                        $font, $randomString[$i]);
}
// Изпраща картинката към браузъра на клиента
imagepng($image);
?>

Следва добавяне на картинката в index.php скрипта (използваме кода от предишните примери). GET параметър „?rand=<?=rand()?>“ не се използва – той е с цел браузъра да не кешира картинката при натискане на back бутон на браузъра (да, ние сме го помолили вече да не го прави, но дали ще спази тази наша молба? Ако картинката всеки път е с произволно име, решаваме и този проблем… но ако браузъра кешира е index страницата – е тогава няма какво да направим):

<?php
	if(isset($_COOKIE['user']) && isset($_COOKIE['token'])){
		header("Location: login.php");
		exit;
	}
	session_start();
?>
<html><head><title>Login page</title></head>
<body>
<form action="login.php" method="POST">
USER: <input type="text" name="user" /><br />
PASS: <input type="password" name="pass" /><br />
<img src="captcha.php?rand=<?=rand()?>" alt="Security image" /><br />
Image text: <input type="text" name="captcha" /><br /> 
Remember?<input type="checkbox" name="remember" value="1" />
<input type="submit" name="loginbutton" value="Login!" /><br />
</form><br />
<?php
	if(isset($_SESSION['error'])){
		echo $_SESSION['error'];
		session_unset();
		session_destroy();
	}
?>
</body></html>

Накрая добавяме проверка на captcha кода в login.php скрипта (представяме само фрагмент от него):

// Проверяваме за валидност на captcha
function captchaIsValid(){
	return is_string($_POST['captcha']) && $_SESSION['captcha'] == $_POST['captcha'];
}
...
// Проверка за captcha там, където сме установили,
// че потребителя ще се автентикира през POST
if(captchaIsValid()){
   $user = $_POST['user'];
   $pass = $_POST['pass'];
}
else{
   // Съобщение 3 ще е "невалиден captcha код"
   backToIndex(3);
   exit;
}

Допълнителни задачи:

  1. Направете избора на цвят за буква произволен, но така, че да има съществено отличаване от фона;
  2. Направете цвета на фона произволен, като се съобразите с условието да се отличава от цвета на буквите;
  3. Направете по няколко произволно генерирани линии, които да пречат на разпознаването на буквите чрез функции като imageline и imagearc;
  4. Добавете шум чрез добавяне на разноцветни точки с различни големини чрез imagesetpixel;
  5. Премахнете потенциално проблемни комбинации от букви – например 0 и O, I, 1 и l и др.;
  6. Направете текста да е с променлива дължина от 5 до 10 символа.

 



4 коментара


  1. Иван каза:

    Тези капчи отдавна се преминават от ботовете все едно са топъл нож през масло. Кажи нещо за другите начини за защита от автоматизиран достъп.

  2. Писал съм.

    При captcha има едно много интересно свойство – ако сам си я напишеш (даже смотана и проста да е) + не си достатъчно популярен, работи идеално :) Ползваш ли готова или пък си от големите играчи – изгонил си само loosers :)

  3. Иван каза:

    > Писал съм.

    Сещам се, но ще е уместно да сложиш един линк :)

    Няма идеална капча. Всичко което може да се OCR-не, го правят. Ако ботове не минават през капчата, това означава че просто сайта не им е влязъл в полезрението ;)

  4. Даже не е ОСR. Достатъчно е да има голям сайт с много трафик под контрола на хакера. Например ако контролира голям торент сайт, бота прави следното:

    – Влиза на нашия сайт, взима картинката
    – Слага я в торент сайта за пореден клиент, който иска да изтегли нещо
    – Клиента въвежда кода, хакера го взима и го пуска на нашия сайт
    – Нашият сайт връща отговор дали е ОК или не. Ботът връща същия отговор и на клиента в торент тракера.

    Transparent captcha hack :)

Добави коментар

Адресът на електронната поща няма да се публикува


*