Leniwce.com | blog technologiczny
Generowanie kodów CAPTCHA w PHP
Bartosz Lewandowski, 2009-10-31 15:51:02
kategoria: PHP

Niestety i nasz blog padł ofiarą bota, który uparcie wpisywał idiotyczne komentarze do jednego z artykułów. Moją reakcja na problem było zaimplementowanie mechanizmu Captcha, który w teorii ma uniemożliwić automatom podszywanie się pod ludzi. Ale tylko w teorii, bo większość mechanizmów captcha jest złamana.

Captcha - Completely Automated Public Turing test to tell Computers and Humans Apart, po naszemu i w skrócie będzie to: Test Turinga rozróżniający człowieka od maszyny.
Skąd taka nazwa? Nie mam pojęcia, jest jednak moim zdaniem jest co najmniej na wyrost. A biedny Alan Turing w grobie się przewraca. Zresztą zobaczcie sami, czym jest test Turinga.

Obrazek captcha ma być łatwo rozpoznawalny dla człowieka, jednak ma stanowić trudność dla automatów. Należy pamiętać, że do łamania zabezpieczeń captcha wystarczy odpowiednio przygotowane oprogramowanie OCR.

Przygotowałem więc klasę Captcha, której zadaniem jest generowanie i weryfikacja kodów-obrazów. Zdaję sobie sprawę, że mechanizm, który zaimplementowałem ma parę słabości i warto by było wprowadzić kilka usprawnień, np. zmieniać krój czcionek poszczególnych znaków, nie trzymać stałej odległości pomiędzy znakami, powyginać fonty, etc.
Zresztą o słabości captcha poczytajcie tu: http://ocr-research.org.ua/list/ppage/1.html

Jednak, w naszym wypadku zabezpieczenie powinno być wystarczające. Raczej nie muszę się obawiać, że ktoś będzie budować sieć neuronową w celu łamania zabezpieczeń na Leniwcach. Są smaczniejsze kąski :).

Oddaje więc klasę, której zadaniem jest generowanie captcha. Jej zaletą jest banalne użycie.
Przykład działania zobaczycie na stronie testowej http://www.leniwce.com/examples/captcha/ lub po prostu dopisując komentarz do artykułu.

Cały kod przykładu wygląda tak:

 
< ?php
include "Captcha.php";
$c = new Captcha("tmp/");
$code = $c->makeCheckImage();
if (isset(__GET["action"]))
{
	if ($c->checkCode(__POST["wpisanyKod"],__POST["weryfikacja"])) 
		echo "Kod OK"; 
	else 
		echo "Sorki, zly kod :(";
}
echo "< h2>Wpisz kod z obrazka< /h2>";
echo "< form method='post' action='?action=test'>
< img src='tmp/".$code.".jpg' style='margin-right: 10px;vertical-align:middle;'>
< input type='text' name='wpisanyKod'/>< br/>
< input type='hidden' value='$code' name='weryfikacja'/>< br/>
< input type='submit' value='Test'/>
< /form>";
?>
 
 

Aby więc wykorzystać klasę Captcha, wystarczy na początku utworzyć obiekt Captcha. W konstruktorze podajemy ścieżkę, gdzie będą zapisywane powstałe pliki graficzne:

$c = new Captcha("tmp/");

Teraz generujemy kod-obraz captcha. Zwrotnie otrzymamy ciąg znaków zakodowany mechanizmem md5. Będzie on służył do weryfikacji wprowadzonego przez użytkownika kodu. By utrudnić atak tęczowymi tablicami, do hash-a md5 oprócz samego kodu dodana jest sól, w tym wypadku solą jest adres IP klienta i stały ciąg znaków.

$code = $c->makeCheckImage();

W samym formularzy dodamy więc prezentacje obrazka, pole na wpisanie kodu, oraz ukryty element z kodem weryfikacyjnym:
 
< img src='tmp/".$code.".jpg' style='margin-right: 10px;vertical-align:middle;'>
< input type='text' name='wpisanyKod'/>
< input type='hidden' value='$code' name='weryfikacja'/>
 
 

Weryfikacja wprowadzonego przez użytkownika kodu odbywa się w metodzie checkCode, gdzie jako argumenty podajemy wartość wprowadzoną przez użytkownika oraz kod weryfikacyjny przesłany w formularzu.
 
if ($c->checkCode(__POST["wpisanyKod"],__POST["weryfikacja"])) 
 echo "Kod OK"; 
 else 
 echo "Sorki, zly kod :(";
 


Podsumowanie

W tej wersji klasa Captcha zapisuje pliki graficzne na dysku. Przygotowałem metodę czyszcząca katalog z grafikami (cleanUp, wywołuje się automatycznie). Można jednak tak zmodyfikować program, by obrazki nie były zapisywane do bazy a generowane przez PHP do przeglądarki. W wolnej chwili postaram się tę zmianę wprowadzić.

W kodzie klasy są wprowadzone komentarze, nie będę więc zajmować się jej szczegółowym opisem. Dodam jeszcze, że należy pamiętać aby wgrać czcionkę GDF na serwer – w tym wypadku jest to plik font.gdf. Czcionka jest w archiwum razem z klasą i przykładem. W archiwum jest również katalog tmp. Aby przykład działał, upewnijcie się, że serwer będzie miał prawo zapisu do tego katalogu!

Do pobrania: captcha.zip (źródło wraz z przykładem).

Powiązane artykuły
PHP/JQuery – zakładki (taby) w kilku liniach kodu. (2009-08-17)


Komentarze


Razz [2010-02-28 16:48:08]
Osobiście polecam zamiast kodów obrazkowych losowe działania matematyczne, tylko dość proste, bo skomplikowane czasem odstraszają mało ambitnych czytelników.
Artur [2010-03-04 14:15:48]
Niestety przez coraz mądrzejsze systemy, obchodzące te zabezpieczenia o wiele łatwiej czytelnikowi obliczyć ile to jest 5/1 niż wczytać się w skomplikowane kody zabezpieczające.
Bartek [2010-04-28 21:30:53]
Ciągle mam ochotę napisać sieć neuronową łamiącą kody Captcha. Jak tylko znajdę czas to się pojawi tu na blogu.
MHunter [2010-07-22 10:21:24]
Thanks! I will try to use it in my blog
NalesnikLD [2011-03-18 11:59:52]
może i działa na potencjalne roboty czy nie kombinujących, ale wystarczy otworzyć jedną stronę z tym captcha, wykopiować md5, i rozpoznać, i otwierając każdą następną stronę podmienić jej md5 i wysłać tą raz rozpoznaną wartość.
Bartek [2011-03-23 22:30:40]
Jak napisalem na wstepie - blog padl ofiarą bota. Jak widać, zabezpieczenie dziala juz od roku.
Czyli jest skuteczne.
DDD [2011-11-01 22:30:51]
:)

Dodaj komentarz:
Autor:*

WWW:

Treść:*

Wprowadź kod zabezpieczający*:


        * - pola wymagane
Kategorie
C# (13)
Inne (6)
Java (3)
Matlab (1)
OpenGL (1)
PHP (2)


Najnowsze wpisy

Ostatnie komentarze