CAPTCHA

Gray 08.08.08 18:44

Kuvavarmennus jolla tarkistetaan että käyttäjä on ihminen eikä botti.

 Tekstiversio  Arvo: 9 (21 ääntä)  Äänestä: +  -
Tällä koodipätkällä saa kätevästi estettyä spammi- ym. bottien käytön. Käyttäjä antaa kuvassa näkyvän koodin ja sitä verrataan $_SESSION['captcha'] muuttujassa olevaan.

<?php
 //aloitetaan sessio
 session_start();

 //lähetetään selaimelle tieto että kuvaa on tulossa
 header("Content-type: image/png");

 //luodaan 200x80-pikselin kokoinen kuva
 $kuva=imagecreate(200,80);

 //määritetään taustan ja tekstin väri
 $tausta=imagecolorallocate($kuva, 255, 255, 255);//valkoinen
 $musta=imagecolorallocate($kuva,0,0,0);//musta
 //fontti jolla teksti piirretään
 //laita jokin fonttitiedosto samaan kansioon tai muuta polku oikeaksi
 $fontti = dirname(__FILE__).'/fontti.ttf';

 //luodaan sattumanvarainen captcha
 $captcha = random_letters(6);

 //piirretään captcha
 imagettftext($kuva, 30, rand(-10,10), 10, 55, $musta, $fontti, $captcha);

 //tallennetaan captcha sessiomuuttujaan
 $_SESSION['captcha'] = $captcha;

 //tehdään kuvan tunnistaminen boteille vaikeammaksi
 //Amplitudimodulaation kuvaaja: y=c*sin(x/a)*sin(x/b)
 $pisteet = array();
 $CC = rand(5,20);//kuvaajaan vähän sattumanvaraisuutta...
 $AA = rand(4,12);
 $BB = rand(4,8);

 //lasketaa x ja y arvot piste kerrallaan
 for ($x=1; $x<200; $x=$x+1)
  {
    //käytetään amplitudimodulaation funktiota
    $y = $AA*sin($x/$CC)*sin($x/$BB);//y:n arvo
   
    //lisätään x ja y arvot taulukkoon
    $pisteet[] = $x;
    $pisteet[] = 40-$y;
  }
 //lasketaan arvojen määrä
 $pisteetMaara = count($pisteet)/2;

 //piirretään kuvaaja
 for ($i=0; $i<$pisteetMaara-1; $i++)
  {
   imagelinethick($kuva, $pisteet[2*$i], $pisteet[1+2*$i], $pisteet[2+2*$i], $pisteet[3+2*$i], $musta, 3);   
  }

 //asetetaan kuvaan muutama filter (http://fi.php.net//imagefilter)
 imagefilter($kuva, IMG_FILTER_EMBOSS);
 imagefilter($kuva, IMG_FILTER_GAUSSIAN_BLUR);

 //laitetaan kuva PNG muotoon
 imagepng($kuva);

 //poistetaan kuva muistista
 imagedestroy($kuva);

 //funktio joka arpoo sattumanvaraisia kirjaimia ja numeroita
 function random_letters($merkkienmaara)
  {
    $merkit = array('1', '2', '3', '4', '5', '6', '7', '8', '9'); //tähän voi laittaa myös kirjaimia, jokainen muokatkoon haluamakseen...
    $merkkien_maara = count($merkit);
     for ($a = 0; $a < $merkkienmaara; $a++)
      {
       $rand = rand(0, $merkkien_maara-1);
       $mjono = $mjono.$merkit[$rand];
      }
    return $mjono;
   }

 //funktio joka piirtää paksumpaa viivaa kuin php:n oma imageline()
 //Huom. kopioin tämän funktion suoraan php.net:stä, joten kommentointi on englanniksi
 function imagelinethick($image, $x1, $y1, $x2, $y2, $color, $thick = 1)
 {
     /* this way it works well only for orthogonal lines
     imagesetthickness($image, $thick);
     return imageline($image, $x1, $y1, $x2, $y2, $color);
     */

     if ($thick == 1) {
         return imageline($image, $x1, $y1, $x2, $y2, $color);
     }
     $t = $thick / 2 - 0.5;
     if ($x1 == $x2 || $y1 == $y2) {
         return imagefilledrectangle($image, round(min($x1, $x2) - $t), round(min($y1, $y2) - $t), round(max($x1, $x2) + $t), round(max($y1, $y2) + $t), $color);
     }
     $k = ($y2 - $y1) / ($x2 - $x1); //y = kx + q
     $a = $t / sqrt(1 + pow($k, 2));
     $pisteet = array(
         round($x1 - (1+$k)*$a), round($y1 + (1-$k)*$a),
         round($x1 - (1-$k)*$a), round($y1 - (1+$k)*$a),
         round($x2 + (1+$k)*$a), round($y2 - (1-$k)*$a),
         round($x2 + (1-$k)*$a), round($y2 + (1+$k)*$a),
     );
    imagefilledpolygon($image, $pisteet, 4, $color);
    return imagepolygon($image, $pisteet, 4, $color);
 }
?>

ddf 21:16 8.8.08 
Itse olen yleensä toteuttanut lyhyiden satunnaisten kirjainyhdistelmien generoinnin siten, että olen ottanut halutun verran merkkejä tämän palauttamasta merkkijonosta:

PHP
sha1(uniqid(rand(), true));
 

Yläraja merkkijonon pituudelle on tällöin tietenkin sha1-tiivisteen pituus, joka on muistaakseni 40 merkin hujakoilla. Mielestäni hieman helpompaa, kuin määritellä erikseen, mitä kirjaimia/numeroita käytetään. Tietenkin jos halutaan nimenomaan esimerkiksi pelkkiä numeroita - kuten olet esimerkissäsi käyttänytkin - niin silloin tuo sinun tapasi on parempi. CAPTCHA:n murtamisen vaikeuttamisen kannalta tietenkin olisi hyvä, että aina käytettäisiin sekä numeroita että kirjaimia.
ajv 17:12 9.8.08 
Ja seuraavaksi koodivinkiksi ohjelma, joka murtaa tämän :) Ihan hyvä pätkä, plussaa tuli.
Jazmo 17:20 14.8.08 
CAPTCHAT ovat muuten vaan ihan perseestä. Generoikaa ennemmin vaikka "Laske yhteen viisi ja neljä" tms.
ape10 14:33 16.8.08 
captchat eivät vain oikein toimi :/

Käyttäjän kannalta huomattavasti parempi ratkaisu on esim. juuri tuo yksinkertainen laskutehtävä tai vaikka kissakuvien erottaminen autokuvista.
editoitu: 05:49 17.8.08
Grez 01:56 17.8.08 
ape10, miten kissakuva on parempi ratkaisu jos kerran kissakuva (eli captcha) ei toimi?

Eli siis captcha = Completely Automated Public Turing test to tell Computers and Humans Apart
Termi voi siis tarkoittaa yhtä hyvin tekstin kuin kissojen tunnistamista

Nuo laskutehtävät on koneellisesti todella helppo ratkaista. Ne eivät siis ole captchoja, koska niiden toimiminen perustuu niiden harvinaisuuteen, eli spämmerit ei vielä tunne niitä. Varsinkin suomeksi toimii ainakin toistaiseksi hyvin, koska ketään ulkomaista toimijaa ei kiinnosta spämmätä suomalaisille foorumeille (jossa sitä olen nähnyt käytettävän) niin paljon, että lähtisivät sitä opettamaan koneilleen. Suomalaiset toimijat taas ei lähde spämmäämään lainsäädännön takia. Mutta tästä syystä niitäkään ei voi suositella mihinkään suosittuun softaan sisällytettäväksi, koska sitten ne lakkaisivat toimimasta.

Yleisesti ottaen lähes mikä tahansa systeemi, joka ei ole käytössä missään muualla, toimii hyvin sivustolla, joka ei ole kovin suosittu. Esimerkkinä nyt vaikka sosiaalisesti rajoittuneiden viritys, joka on estänyt ulkomaisen spämmin ilmestymisen kommentteihin äärettömästä yksinkertaisuudestaan huolimatta.
ape10 21:55 19.8.08 
Grez, käytin ilmeisesti virheellisiä termejä, joten korjataanpas. Tämän esimerkin tapaiset captchat on varmasti helposti luettu koneellisesti.

Tuo on muuten myös ihan totta kun puhuit näiden systeemien toimivuudesta. Täysin uniikit järjestelmät toimivat. Kun sama leviää häviää captchan tehokin :|

Akiro 12:48 21.8.08 
Niin ja tässähän ei kysytä äänestettäessä tykkääkö arvostelija kyseisenlaisesta CAPTCHA:sta vaan koodipätkän tasosta, eli tuo kannattaa pitää mielessä ku päättää tuon +/-.
Jazmo 09:20 22.8.08 
Joo, en laittanu +/- sen puolesta.
ape10 15:00 24.8.08 
Akiro kirjoitti:
Niin ja tässähän ei kysytä äänestettäessä tykkääkö arvostelija kyseisenlaisesta CAPTCHA:sta vaan koodipätkän tasosta, eli tuo kannattaa pitää mielessä ku päättää tuon +/-.

Niin, koodivinkkinä tämähän on loistava. Itse en olisi ymmärtänyt tehdä tuota näin. + toteutuksesta, - ideasta