Securitate Web: Cod Captcha
In vremurile noastre programarea este foarte accesibila, atat de accesibila incat dupa 7 zile(fara sa fii avut contact cu limbaje de programare niciodata) in PHP ti-ai construit propriul bot ce poate stresa administratorii in cel mai cumplit mod.
Vad tot mai des formulare de contact neprotejate prin nimic, fara cod captcha, sau si mai rau iti baga o adunare vizibila din sursa. Pai serios vorbind acum, el ca programator web, nu stie ca un bot lucreaza cu sursa? Neatentia programatorilor web la securitate este jignitoare, scuza lor intotdeauna este ca „Nimeni o sa faca un bot special pentru site-ul meu”. Ei pe naiba, sa-mi dea un mail ca il fac eu, dar daunele suportate de ei.
In acest tutorial vom invata despre captcha-uri, nu articole de 3 randuri unde prezint ce este un captcha si afisez 3 linii de cod dupa plec sa ma culc, un tutorial amanuntit unde vom experimenta mai multe metode de captcha.
Ce este un captcha?
Cu cat un captcha este mai complicat, mai intors, mai impodobit, cu atat mai imposibila este spargerea lui. Chiar si un captcha simplu, un text drept cu un font default pe o imagine alba este foarte greu de spart, algoritmii pentru OCR fiind foarte complicati.
Cum folosim captcha in PHP?
- Un fisier PHP genereaza un cod captcha, il salveaza intr-o sesiune, iar apoi il afiseaza ca imagine
- Vizitatorului ii este afisat codul captcha si un input unde sa introduca ce caractere vede in imagine
- Datele sunt trimise prin POST sau GET la alta pagina(cand vizitatorul apasa pe submit sa introduca comentariul de exemplu)
- Acea pagina verifica ce a trimis el prin POST sau GET cu ce este in sesiune
- In caz ca codul nu a fost introdus corect il anunta ca a gresit si inchide scriptul(exit)
Partea cea mai complicata, crearea imaginii, va fi subiectul principal al acestui articol. Dar si celelalte vor fi explicate.
Pentru intelege acest articol ai nevoie deja sa intelegi lectia Generare imagini cu PHP
Introducere | Captcha Simplu
Structura fisierelor
Crearea imaginii
Cod captcha.php:
<?php session_start(); $image_width = 200; $image_height = 60; $ih = imagecreate($image_width, $image_height); $negru = imagecolorallocate($ih, 0, 0, 0); // background $rosu = imagecolorallocate($ih, 255, 0, 0); // text imagefill($ih, 0, 0, $negru); // umplem backgroundul cu negru $cod_captcha = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 5); $_SESSION['cod'] = $cod_captcha; // salvam codul in sesiune putenv('GDFONTPATH=' . realpath('fonts/')); // setam folderul pentru fonturi $font = 'KiteOne'; # Cu coords centram text-ul. $coords = imagettfbbox(29, 0, $font, $cod_captcha); // Coordonate pentru a centra textul $start_x = ($image_width - $coords[2])/2; imagettftext($ih, 29, 0, $start_x, 40, $rosu, $font, $cod_captcha); header('Content-type: image/png'); imagepng($ih); ?>
Pagina unde afisam captcha
Cod contact.html:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Contacteaza-ma</title> </head> <body> <form action="submit-contact.php" method="POST"> <table cellpadding="5" border="3" style="width:50%; margin:0 auto;"> <tr> <td>Subiect</td> <td><input type="text" name="subiect"></td> </tr> <tr> <td>Mesaj</td> <td> <textarea name="mesaj" style="width:90%;" rows="3"></textarea> </td> </tr> <tr> <td>Captcha</td> <td> <img src="captcha.php" id="captcha" onclick="this.src='captcha.php?'+new Date().getTime()" alt=""> <br><sub>* Scrieti textul din imagine in casuta de mai jos</sub><br> <input type="text" name="captcha"> </td> </tr> </table> <input type="submit" value="Trimite mesaj" style="margin-right:25%; float:right;"/> </form> </body> </html>Folosim la javascript in adresa url si time-ul curent ca un bypass pentru "cache-ul" care se face la imagini.
Validarea captcha-ului
Cod submit-contact.php:
<?php session_start(); if($_SERVER['REQUEST_METHOD'] != 'POST'){ // Metoda de REQUEST nu este POST header('Location: contact.html'); exit; } if(isset($_SESSION['captcha'])){ if($_POST['captcha'] == $_SESSION['captcha']){ // Aici am trimite emailul dar este doar un exemplu echo 'Mail trimis cu success!'; } else{ echo 'Codul captcha este gresit! Veti fi redirectionat inapoi in 3 secunde.'; header('Refresh: 3; url=contact.html'); exit; } unset($_SESSION['captcha']); // stergem captcha-ul } else{ echo 'Captcha-ul nu a fost primit! Veti fi redirectionat inapoi in 3 secunde.'; header('Refresh: 3; url=contact.html'); exit; } ?>
Demo
Securizare Imagine captcha
Font aleatoriu
Structura fisiere noua
Downloadati fonturile din arhiva aceasta nu pierdeti timpul luandu-le pe rand.Cod captcha.php:
<?php session_start(); $image_width = 200; $image_height = 60; $ih = imagecreate($image_width, $image_height); $negru = imagecolorallocate($ih, 0, 0, 0); // background $rosu = imagecolorallocate($ih, 255, 0, 0); // text imagefill($ih, 0, 0, $negru); $cod_captcha = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 5); $_SESSION['captcha'] = $cod_captcha; // salvam codul in sesiune putenv('GDFONTPATH=' . realpath('fonts/')); // setam folderul pentru fonturi $fonturi = array( 'Playball', 'JustMeAgainDownHere', 'Englebert', 'Yesteryear', 'KiteOne', 'Spirax', 'Nosifer', 'JollyLodger', 'Davonshire', 'Finger Paint' ); $font = $fonturi[ rand(0, count($fonturi)-1) ]; // alegem un font random $coords = imagettfbbox(29, 0, $font, $cod_captcha); // Coordonate pentru a centra textul $start_x = ($image_width - $coords[2])/2; imagettftext($ih, 29, 0, $start_x, 40, $rosu, $font, $cod_captcha); header('Content-type: image/png'); imagepng($ih); ?>
Deoarece fonturile sunt foarte periculoase cand vine vorba de majuscule sau minuscule trebuie sa lasam vizitatorul sa le bage cum doreste, deci schimbam putin validarea.
Cod submit-contact.php:
<?php session_start(); if($_SERVER['REQUEST_METHOD'] != 'POST'){ // Metoda de REQUEST nu este POST header('Location: contact.html'); exit; } if(isset($_SESSION['captcha'])){ if(strtolower($_POST['captcha']) == strtolower($_SESSION['captcha'])){ // Aici am trimite emailul dar este doar un exemplu echo 'Mail trimis cu success!'; } else{ echo 'Codul captcha este gresit! Veti fi redirectionat inapoi in 3 secunde.'; header('Refresh: 3; url=contact.html'); exit; } unset($_SESSION['captcha']); // stergem captcha-ul } else{ echo 'Captcha-ul nu a fost primit! Veti fi redirectionat inapoi in 3 secunde.'; header('Refresh: 3; url=contact.html'); exit; } ?>
Un demo aveti pe pagina aceasta
Linii
Cod captcha.php:
<?php session_start(); $image_width = 200; $image_height = 60; $ih = imagecreate($image_width, $image_height); $negru = imagecolorallocate($ih, 0, 0, 0); // background $rosu = imagecolorallocate($ih, 255, 0, 0); // text imagefill($ih, 0, 0, $negru); $cod_captcha = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 5); $_SESSION['captcha'] = $cod_captcha; // salvam codul in sesiune putenv('GDFONTPATH=' . realpath('fonts/')); // setam folderul pentru fonturi $font = 'KiteOne'; $coords = imagettfbbox(29, 0, $font, $cod_captcha); // Coordonate pentru a centra textul $start_x = ($image_width - $coords[2])/2; imagettftext($ih, 29, 0, $start_x, 40, $rosu, $font, $cod_captcha); # Urmeaza sa cream un numar intre 5 si 15 de linii cu acceasi culoare ca textul $linii = rand(5,15); for ($i=1; $i < $linii; $i++) { imageline($ih, rand(1,$image_width) , rand(1,$image_height), rand(1,$image_width) , rand(1,$image_height), $rosu); } header('Content-type: image/png'); imagepng($ih); ?>
Un demo la pagina aceasta
Puncte
- 1. Imi place cum arata
- 2. Nu incurca
- 3. Nu poate face nimic rau, decat bine
Cod captcha.php:
<?php session_start(); $image_width = 200; $image_height = 60; $ih = imagecreate($image_width, $image_height); $negru = imagecolorallocate($ih, 0, 0, 0); // background $rosu = imagecolorallocate($ih, 255, 0, 0); // text imagefill($ih, 0, 0, $negru); $cod_captcha = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 5); $_SESSION['captcha'] = $cod_captcha; // salvam codul in sesiune putenv('GDFONTPATH=' . realpath('fonts/')); // setam folderul pentru fonturi $font = 'KiteOne'; $coords = imagettfbbox(29, 0, $font, $cod_captcha); // Coordonate pentru a centra textul $start_x = ($image_width - $coords[2])/2; imagettftext($ih, 29, 0, $start_x, 40, $rosu, $font, $cod_captcha); $linii = rand(5,15); for ($i=1; $i < $linii; $i++) { imageline($ih, rand(1,$image_width) , rand(1,$image_height), rand(1,$image_width) , rand(1,$image_height), $rosu); } # Adaugam 200 de puncte for ($j=0; $j < 200; $j++) { $x = rand(1,$image_width); $y = rand(1,$image_height); # Folosesc imageline pentru a desena un punct deoarece are aceleasi coordonate de pornire ca de oprire imageline($ih, $x, $y, $x , $y, $rosu); } header('Content-type: image/png'); imagepng($ih); ?>Demo la pagina aceasta
Tags: Tutoriale, Programare Web, Php