Captcha med gdLib

Tags:    php
Skrevet af Jonas (Decko) @ 22.02.2007

Hvad er en Captcha?


Captcha[url=http://www.captcha.net][1][/url] (Completely Automated Public Turing test to tell Computers and Humans Apart). Som forkortelsen antyder er det en test der bruges til at finde ud af om en bruger er et menneske, eller en computer. Dette kan bestå af f.eks. et billede med noget tekst der kan være roteret, farvet og fyldt med streger og mønstrer. På den måde gør man det svært for computere at se hvad der egentlig står.


Eksempel på captcha fra et andet script jeg har lavet.


Hvad bruges det til?


En Captcha bruges normalt når man skal oprette en bruger på et forum, skrive en kommentar på en blog for at forhindre den pågældende blog eller forum i at blive spammet af robotter med "gode tilbud".

Før vi går i gang


I denne artikel bruger jeg gdLib til at tegne med og artiklen er nok en del nemmere at forstå hvis du har en smule erfaring med det. Men jeg forsøger at kommentere på bedste vis, så alle kan være med.

Lad os komme i gang med noget kode!


Det første vi gør er at lave nogle indstillinger for vores captcha, kommenteret på bedste vis ;). Session_start() skal vi bruge senere for at gemme ordet.

Fold kodeboks ind/udKode 


Den overstående kode skulle være til at forstår så vi går straks videre med at generere et tilfældigt ord.

Fold kodeboks ind/udKode 


Det der sker er, at der kopieres et par tilfældige bogstaver ud af vores $config['characters'] som jo bestemmer hvilke tegn der må bruges. Antallet af tegn i ordet bestemmes af $config['wordlength'].

Efter vi har genereret vores tilfældige ord vil vi gerne gemme det så vi senere kan tjekke om brugeren indtastede det korrekte. Vi gemmer det i en session sådan så vi kan hente det fra en hver anden php-fil. For at højne sikkerheden gemmer vi det som en MD5-hash.

Fold kodeboks ind/udKode 


Design af billedet


Nu da vi har fået genereret et tilfældigt ord og gemt det til senere brug, er det tid til at lave det billede som brugeren skal kunne læse ordet fra. Her har man sådan set frie hænder til at lave hvad man vil. Man skal bare huske på en ting, jo mere avanceret billedet er, desto sværere bliver det for brugeren at aflæse det. En captcha der er for svær at tyde kan føre til irritation af brugeren og derved også få brugeren til ikke at gide besøge siden igen.
Med det i tankerne går vi i gang med designet.
Jeg vil lave et relativt simpelt billede med tilfældige streget som baggrund og roteret tekst til at vise ordet med.

Vi starter med at oprette vores "lærred" og give dette en hvid baggrundsfarve.

Fold kodeboks ind/udKode 


Herefter tegner jeg 10 forskelligfarvede streger og tilfældige længder. Her benytter jeg funktionen imageline som har 6 parametre.

1. Billedet der skal tegnes på.
2. Startpunkt i x-aksen.
3. Startpunkt i y-aksen.
4. Slutpunkt i x-aksen.
5. Slutpunkt i y-aksen.
6. Farven på stregen.

Fold kodeboks ind/udKode 


Til slut placerer vi vores ord på billedet ved hjælp af funktionen imagettftext. Funktionen vil have 8 parametre som er:

1. Billedet vi vil tegne på.
2. Størrelsen på teksten.
3. Vinklen på teksten.
4. Startpunkt på x-aksen.
5. Startpunkt på y-aksen.
6. Farven på teksten.
7. Skrifttypen der skal bruges.
8. Den egentligt tekst.

Da jeg gerne vil have at bogstaverne har forskellige farver bliver jeg nødt til at skrive et bogstav af gangen.

Fold kodeboks ind/udKode 


I koden ganger jeg $i med 18. Dette er for at lave mellemrum mellem bogstaverne. Dette kan ændres alt efter behag.
Derudover tager jeg et tilfældigt tal mellem -40 og 40 som er den vinkel det enkelte bogstav skal have. Dette kan selvfølgelig også ændres efter behag.

Til slut fortæller vi browseren at vi giver den et png-billede. Hvis vi ikke gjorde det, ville browseren tro det var tekst og derfor vise en masse mystiske tegn istedet for billedet.

Fold kodeboks ind/udKode 


Nu skulle den samlede kode gerne ligne noget i den her retning.

captcha.php
Fold kodeboks ind/udKode 


Du kan nu teste det på din hjemmeside og konstatere at det virker (forhåbenligt ;)).


Eksempel på vores færdige captcha

Hvordan bruger man det så?


Nu når vi er nået så langt som at have lavet billedet vil vi også gerne vide hvordan det bruges i praksis.
Til dette formål laver jeg et simpelt eksempel som viser en tekst hvis man skriver det rigtige ord.

captcha_sample.php
Fold kodeboks ind/udKode 


Afrunding, hvad kan gøre bedre?


Som du sikkert har lagt mærke til skelner vi mellem store og små bogstaver. Dette kan vi rette på 2 måder. Enten ved at fjerne alle store bogstaver fra vore konfiguration eller ved at konvertere ordet til små bogstaver inden vi gemmer det. På den måde vil billedet stadig vise store og små bogstaver og derfor vil vi ikke slække på sikkerheden.
Dette kan gøres ved at rette en enkelt linje i vores captcha-script.

Fold kodeboks ind/udKode 


For en sikkerheds skyld konverterer vi også brugerens input til små bogstaver i vores test-fil, skulle brugeren have gjort sig umage og skelnet mellem store og små bogstaver ;).

Fold kodeboks ind/udKode 


Nu da vi er helt færdige er det bare at gå i gang med at lege med scriptet og finde måder at gøre det bedre på. Se evt. http://www.php.net/gd for at få en liste over de funktioner gdLib har. Der skulle være masser at gå i gang med.

Jeg håber artiklen her kan hjælpe dig med at holde din side fri for spam samt at have givet dig en idé om hvad gdLib kan bruges til.

Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (9)

User
The-Freak @ 23.02.07 07:26
Jeg har lidt svært ved at se hvad grunden til at bruge md5 til at hashe $captcha. $_SESSION er en server variabel, og den kan ALDRIG ses fra brugerens side, medmindre du direkte udprinter sessionen til brugeren. Så i midt hode er md5 bare et spild af hastighed.

Derudover vil jeg sige at det er lidt dårlig programeringsskik at du tilføjer et bogstav til en variabel som du ikke egentlig har oprettet - Her hentyder jeg selvffølgelig til der hvor $captcha bliver generet. Det kode du har skrevet er sådan set fint nok, men det er en dårlig skik, ikke at erklære sin variabel først.

Ellers en udemærket artikel, det bliver en 3'er herfra.
User
Jens P. Svensson @ 23.02.07 17:09
glemmer du ikke lige at teste om key nu også er sat?

Hvis brugeren den ondsindet spammer nu f.eks. bare lader være med at loaded dit billed(kan godt lade sig gøre) bliver den aldrig sat og så godkendes brugeren så længe han undlader at skrive(måske).

Mener iøvrigt jeg læste et eller andet sted at den før omtalte spammer var blevet så modernet at han nu var er udstyret med et programmer til billedgenkendelse for lige netop at bryde sikkerheden i en Captcha. Hvis det tilfældet er en Captcha kun en irititation og en server udgift.

For at øge sikkerheden kunne du tilføje at bogstaverne var et mix af fonte og størrelser, ikke rette linier.

Og hvis du absolut vil spare server cpu bør du overveje ikke at kigge i et array efter værdier du aldrig ændre men lave værdierne til konstanter, en ordentlig engine vil indsætte værdien af konstanten ved indlæsning af scriptet.

Dog må jeg indrømme at din Captcha er bedre end nogen jeg har lavet :).

Siden den er bedre end min og skrevet forståeligt må jeg vel give 4 :), den eneste indsigelse jeg har til forståeligheden er at du nester funktionskald i funktionskald mens det nok er bedre cpu-mæssigt er det ikke voldsomt læsligt.



User
Troels @ 23.02.07 18:11
Jeg er enig med The-freak i at det er overflødigt at hashe $captcha, men ironisk nok er det faktisk det der redder din captcha, da md5 returnerer en streng, streng == null er false. hvis ikke brugte md5 kunne man lade være med at hente billedet og lade være med sende captcha med i postdata. dette skal tages i betragtning.

Herudvor bør der være et maksimalt antal retries pr. billede, samt et maks antal billeder man kan få på en session.

sessions variablen bør unsettes når man er lukket igennem, ellers kan man bare lade være med at hente et nyt billede og spamme videre.

Jeg tror også at det her ville havde været en god ting at pakke ned i et object, omend tradionerne for dette ikke er så store blandt php udviklere.

Jeg ville ikke være så bekymret omkring ocr programmer, såfremt at man kun bliver lukket igennem engang per billede. det er trods alt et meget urimeligt forhold mellem server og spammer.

når det så er sagt, så synes at artiklen er glimrende struktureret uden latterlige dikkedarer. Sproget er let forståeligt. Indholdsmæssigt synes jeg den er for svær til en nybegynder rating.

3 thumbs herfra
User
Niels @ 07.05.07 15:03
Glimrende artikel.
Lige noget jeg kunne bruge. Du glemmer dog at skrive $config['width']/$config['height'] til at starte med...

4/5
User
Stefan E. Nielsen @ 23.05.07 17:48
Mht til folk der klager over at han gemmer captcha'en som md5 hash så vil tro at det kan skyldes at php har en indstilling til sine sessions hvor data enten gemmes som filer på serveren eller som cookies hos brugeren. i de tilfælde hvor man bruger cookies ville brugeren ellers bare kunne åbne sin cookie og læse captcha'en. men da der kun er gemt en md5 hash hos brugeren kan han ikke bruge det til noget. havde vi ikke brugt md5 hash i det tilfælde ville han bare kunne læse teksten fra captchaen og sende data. derfor ubrugeligt.

5/5 herfra :) kvalitets guide, manglede dog den ovenstående forklaring på hvorfor det er smart at md5 hashe captcha'en
User
Christian B. Andersen @ 28.06.07 16:32
Rigtig god artikel, fik mig godt igang med at få lavet min egen captcha :)
Siger pænt tak..
User
Dennis @ 03.08.07 15:09
God atikkel, der er dog et problem, i alt fald hos mig. Hvis man laver en ren copy/paste (som ikke virker alligevel) saa ender jeg med tFfL0E lige meget hvor meget man refresher :)

Ellers god.
User
Kasper @ 23.03.10 19:58
Jeg får denne fejlmeddelelse:

Billedet “http://localhost/billedUpload/” kan ikke vises, da det indeholder fejl.

Hvad er der galt ? :'(
User
Christian @ 02.05.11 20:51
@Kasper; Det er fordi du kører den på din lokale harddisk. Det er PHP så det skal køres fra en webserver da det er den som afvikler PHP koden ;)
Du skal være logget ind for at skrive en kommentar.
t