Tutorial – Securitate web cu, codul captcha – Web Site

Captcha: În vremurile noastre programarea este foarte accesibilă, atât de accesibilă încât după 7 zile (fără să fii avut contact cu limbaje de programare niciodată) în PHP ți-ai construit propriul bot ce poate stresa administratorii în cel mai cumplit mod.
Văd tot mai des formulare de contact neprotejate prin nimic, fără cod captcha, sau si mai rău îți bagă o adunare vizibilă din sursă. Păi serios vorbind acum, el ca programator web, nu știe că un bot lucrează cu sursa? Neatenția programatorilor web la securitate este jignitoare, scuza lor întotdeauna este că „Nimeni o să facă un bot special pentru site-ul meu”. Ei pe naiba, să-mi dea un mail că îl fac eu, dar daunele suportate de ei.

captcha

În acest tutorial vom învăța despre captcha-uri, nu articole de 3 rânduri unde prezint ce este un captcha și afișez 3 linii de cod după plec să ma culc, un tutorial amănunțit unde vom experimenta mai multe metode de captcha nu ca la alții care se cred programatori cu 3 frimituri :).

Ce este un captcha în web site?

Un cod captcha este un cod cu caractere random (alese la întâmplare) obligatoriu introduse într-o imagine pentru a testa dacă vizitatorul este un bot sau un vizitator uman.
Cu cât un captcha este mai complicat, mai întors, mai împodobit, cu atât mai imposibilă este spargerea lui. Chiar și un captcha simplu, un text drept cu un font default pe o imagine albă este foarte greu de spart, algoritmii pentru OCR fiind foarte complicați.

Cum folosim captcha în web site-urile PHP?

  • Un fișier PHP generează un cod captcha, îl salvează într-o sesiune, iar apoi îl afișează ca imagine
  • Vizitatorului îi este afișat codul captcha și un input unde să introducă ce caractere vede în imagine
  • Datele sunt trimise prin POST sau GET la altă pagină (când vizitatorul apasă pe submit să introducă comentariul de exemplu)
  • Acea pagina verifică ce a trimis el prin POST sau GET cu ce este în sesiune
  • În caz că, codul nu a fost introdus corect îl anunță că a greșit și închide scriptul (exit)

Partea cea mai complicată, crearea imaginii, va fi subiectul principal al acestui articol. Dar și celelalte vor fi explicate.
Pentru a înțelege acest articol ai nevoie deja să ințelegi generarea de imagini cu PHP în web site

Introducere în web site | Captcha Simplu

În prima parte vom crea un captcha foarte simplu.

Structura fișierelor

Structura fișierelor este următoarea:

  • fonts
  • captcha.php
  • contact.html
  • submit-contact.php

Nu uitați să downloadați fontul, click pe el să-l descărcați.

Crearea imaginii în web site

Cream un fișier PHP pe server numit captcha.php, în acel fișier va generat codul, generată sesiunea și generată imaginea.
Cod captcha.php:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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 afișăm captcha în web site

Eu aici îți voi da ca exemplu o pagină de contact, unde când dai click pe imagine îți schimbă codul captcha primit (pentru asta vom folosii JavaScript).

Cod contact.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!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 în adresa url și time-ul curent ca un bypass pentru „cache-ul” care se face la imagini.

Validarea captcha-ului în web site

În această etapă am primit codul captcha din formular și trebuie să vedem dacă este corect.

Cod submit-contact.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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;
}
?>
Securizare Imagine captcha în web site

În această parte lucrăm doar cu fișierul captcha.php, structura rămâne aceeași cu cu cea de la Introducere în web site | Captcha Simplu, dar poate suferii mici modificari pe parcurs.

Font aleatoriu îm web site

O bună practică este folosirea fonturilor extravagante, cât mai ciudate, dar o și mai bună practică este folosirea unui font aleatoriu (adică dintr-o lista de fonturi alegeți unul la întâmplare cu php la fiecare vizită), să complicăm munca bot-ului. Însă nu este bine să exagerați, să folosiți maxim 10 fonturi. În primul va fi necesar să descărcați fonturile și să puneți toate fonturile în folder-ul fonts.

Structura fișiere nouă în webs site

  • fonts
    • KiteOne.ttf
    • Playball.ttf
    • JustMeAgainDownHere.ttf
    • Englebert.ttf
    • Yesteryear.ttf
    • Spirax.ttf
    • Nosifer.ttf
    • JollyLodger.ttf
    • Davonshire.ttf
    • Finger Paint.ttf
  • captcha.php
  • contact.html
  • submit-contact.php

Cod captcha.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?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 când vine vorba de majuscule sau minuscule trebuie să lăsăm vizitatorul să le bage cum dorește, deci schimbăm puțin validarea.

Cod submit-contact.php:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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;
}
?>

Linii

Încă o bună strategie mai este să adăugați linii în captcha. Gândiți-vă logic, linii cu aceeași culoare ca textul, în număr de ~20, vor încurca complet un algoritm slab făcut.

Cod captcha.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?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);
?>

Puncte

Această practică nu am mai vazut-o prin alte părți, dar:

  • 1. Îmi place cum arată
  • 2. Nu încurcă
  • 3. Nu poate face nimic rău, decât bine

Cod captcha.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?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);
?>

Dacă ți-a plăcut acest tutorial și ți-a fost util lasă comentariul tău!

3.665 Vizitatori

Cât de utilă a fost această postare?

Dați click pe o stea pentru a evalua acestă postare!

Rată medie 0 / 5. Număr de voturi: 0

Nu există voturi până acum! Fii prima persoană care evaluează acestă postare.

Îmi pare rău că această postare nu a fost utilă pentru tine!

Să îmbunătățim acest postare!

Spune-mi cum pot îmbunătăți această postare?

Lasă-mi un comentariu!

Acest site folosește Akismet pentru a reduce spamul. Află cum sunt procesate datele comentariilor tale.