KAVALEK.NET 
-Blog
Linux Web development C/C++ Python LaTeX Rallye Ostatní
-Projekty
PyGaM PHP WIS Class PHP Atom Class
-Webdesign
Nabídka Reference
-Ostatní
Aktuality Odkazy Informace
-Osobní
Kontakt CV
-Intranet
Mail server Print server Security camera

KUBUNTU
XHTML Valid
Smarty
jQuery
View Tomáš Kavalek's profile on LinkedIn

Web development: Ochrana proti robotům - CAPTCHA

Zobrazit obsah
Zobrazit komentáře | Zobrazit pouze komentáře

Další zajímavá věc, která se může při tvorbě webu hodit, je ochrana formulářů proti robotům metodou CAPTCHA. Pro implementaci bude použito (X)HTML a PHP. Odkaz na ukázkový kód. Stahovat zdrojové kódy lze z Kavalek Solutions.

Popdůrné funkce

Pro zpřehlednění kódu vytvoříme několik klíčových funkcí, které se budou starat jak o vygenerování kódu, tak pro jeho ověření a zárověň i pro odeslání e-mailu (určeno spíše pro demonstraci celého projektu - není nijak vázáno na generování obrázku). Pomocí funkce randomString() vygenerujeme náhodný řetězec zadané délky, v našem případě budou postačovat 4 znaky - není problém rozšířit (v závislosti na velikosti pozadí - background.png). Funkce returnCaptcha() generuje již samotný obrázek (pomocí knihovny GD). Vygenerovaný kód je načten ze session, je použito pozadí background.png a font font.ttf - fontů lze použít několik a následně upravit tuto funkci, čímž bude obrázek ještě bezpečnější. Poslední funkcí je compareCaptcha(), která porovnává MD5 hash kódu odeslaný z formuláře s MD5 hashem kódu uloženém v session. Poslední podpůrnou funkcí je sendMail(), sloužící k odeslání obsahu formuláře mailem. Funkce by mohla být mnohem jednodušší, ale mám ji takto hotovou pro své projekty, tak jsem ji použil i v demonstraci funkce. Skript captcha.php vytváří již samotný obrázek kódu - ten lze předat HTML tagu img jako parametr src díky header("Content-Type: image/png");.

lib-captcha.php

<?php
  // Random string
  function randomString($length) {
    $string = "";
    for($i = 0; $i < $length; $i++) {
      $char = rand(1, 35);
      $char = ($char < 10) ? $char + 48 : $char + 55;
      if($char == 79) $char++;
      $string .= chr($char);
    }
    return $string;
  }
  
  // Return captcha
  function returnCaptcha() {
    $text   = $_SESSION["captcha"];
    $handle = imagecreatefrompng("./background.png");
    $font = "./font.ttf";
    for($i = 0; $i < strlen($text); $i++) {
      $color  = imagecolorallocate($handle, rand(0,200), rand(0,200), rand(0,255));
      imagettftext($handle, rand(25, 40), rand(0, 20), 20 + ($i * 30), 40, $color, $font, $text[$i]);
    }
    imagecopy($handle, $handle, 0, 0, 0, 0, 150, 50);
    imagepng($handle);
    imagedestroy($handle);
  }
  
  // Compare captcha
  function compareCaptcha($captcha, $hash) {
    if(md5($captcha) == $hash) return true;
    else return false;
  }
?>

lib-sendmail.php

<?php
  // Send mail 
  function sendMail($from, $to, $subject, $body) {
    // Create e-mail MIME headers 
    $headers  = "MIME-Version: 1.0\n";
    $headers .= "Content-type: text/html; charset=iso-8859-2\n";
    $headers .= "X-Priority: 3\n";
    $headers .= "X-MSMail-Priority: Normal\n";
    $headers .= "X-Mailer: php\n";
    $headers .= "Return-Path: <" . $from . ">\n";
    $headers .= "From: \"" . $from . "\" <" . $from . ">\n";
    $headers .= "To: \"" . $to . "\" <" . $to . ">\n";
    $headers .= "Subject: $subject\n";
    
    $emailSource = $headers . "\n" . $body;
  
    if(mail("\"" . $to . "\" <" . $to . ">", $subject, $body, $headers))
      return true;
    else
      return false;
  }
?>

captcha.php

<?php
  header("Content-Type: image/png");
  session_start();
  require("./lib-captcha.php");
  returnCaptcha();
?>

form-sendmail.php

<?php
  session_start();
  require("./lib-captcha.php");
  require("./lib-sendmail.php");
  $_SESSION["captcha"] = randomString(4);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <meta http-equiv="content-type" content="text/html; charset=iso-8859-2" />
  <link rel="stylesheet" type="text/css" href="style.css" />
  <title>Sendmail with CAPTCHA</title>
 </head>
<body>
<?php
  if(isset($_POST["action"]) && ($_POST["action"] == "sendmail")) {
    if(compareCaptcha($_POST["captcha"], $_POST["hash"])) {
      echo("Odesilam mail");
      sendMail($_POST["mail"], "info@my-domain.com", "", $_POST["body"]);
    }
  } else {
?>
 <div class="mailform">
  <form action="form-sendmail.php" method="post" enctype="application/x-www-form-urlencoded">
   <fieldset>
    <legend>Napište nám</legend>
    <p><label for="name">Vaše jméno:</label>&nbsp;<input id="name" name="name" type="text" tabindex="1" /></p>
    <p><label for="mail">E-mail:</label>&nbsp;<input id="mail" name="mail" type="text" tabindex="2" /></p>
    <p><label for="phone">Telefonní číslo:</label>&nbsp;<input id="phone" name="phone" type="text" tabindex="3" /></p>
    <p><img src="captcha.php?<?= htmlspecialchars(SID); ?>" width="150" height="50" title="CAPTCHA" alt="CAPTCHA" /></p>
    <p><label for="captcha">Ověření:</label>&nbsp;<input id="captcha" name="captcha" type="text" tabindex="4" /></p>
    <p><textarea id="body" name="body" rows="1" cols="1" tabindex="5"></textarea></p>
    <input id="hash" name="hash" type="hidden" value="<?php echo(md5($_SESSION["captcha"])); ?>" />
    <input id="action" name="action" type="hidden" value="sendmail" />
    <input type="submit" class="btn" value="Odeslat" tabindex="6" />
   </fieldset> 
  </form>
 </div>
<?php } ?>
</body>
</html>

Jak to funguje a co s tím?

Při načtení stránky s formulářem se aktivuje serverové sezení (tzv. session) a vygeneruje se náhodný čtyřmístný (kombinace písmen a čísel) kód. Tento kód se uloží do session, odkud je použit jak pro samotné vygenerování obrázku (captcha.php), tak i pro vytvoření MD5 hashe pro kontrolu. Hash je po odeslání formuláře ověřen, souhlasí-li s hashem vloženého kódu, je zpracování odeslaných dat korektní, v opačném případě jsou přijatá data zamítnuta.

Jako pozadí lze použít následující obrázek ve formátu PNG, různé fonty lze nelézt Googlem.

CAPTCHA Background

Co dál?

Tento článek sloužil jen jako demonstrace toho, jak jednoduchá je implementace ověřování formuláře metodou CAPTCHA. To však nestačí, nebo spíše tím by vývoj neměl skončit. Bylo by vhodné soustředit použité funkce např. do jedné třídy, aby vše bylo vhodně připraveno pohromadě pro použití ve větším projektu. Přepracovat řešení tak, aby se dalo snadno používat jako šablona, a to buď pomocí nějakého šablonovacího systému (např. Smarty), nebo tak, aby bylo možné blok kódu vkládat univerzálně. Prvním krokem by mohla být úprava action u fomuláře na <?php echo($_SERVER["REQUEST_URI"]); ?>, případně řešení pomocí AJAXu, atd. Každý si může upravit jak mu bude samo vyhovovat. Dále pak ověřování vyplnění povinných položek formuláře, platnost vstupních údajů pomocí regulárních výrazů atd.

Chyba

Díky použití tohoto skriptu na webu cestovní agentury PROWICOMT objevil Vilém Černohorský chybu v MSIE, pokud použil skript na externím webu, vložený pomocí IFRAME. MSIE nechtěl spolupracovat a vše řešil jako nepovolené cookies, nezobrazoval se kód, pouze podklad. Chybně jsem předpokládal kompilaci PHP na hostingu s tagem --enable-trans-sid. Tuto nečekanou chybu jsem vyřešil vkládáním obrázku následujícím způsobem captcha.php?<?= htmlspecialchars(SID); ?>, namísto captcha.php.


07.10.2007 20:39:09 - 1781x
Hodnocení (227)

Rating - 56% 56%

DOBRÉ | ŠPATNÉ

Komentáře k tématu 'Ochrana proti robotům -...' (0 komentářů)

Vložit komentář | Zobrazit pouze komentáře | Nahoru
Ještě nebyl vložen žádný komentář. Pro vložení prvního komentáře klikněte zde.

Vyhledávání

 
Google

Reklama

Knihy
© 2004 - 2008 Tomáš Kavalek - Obsah webu, zdrojové kódy a projekty lze používat a dále šířit dle GNU GPL. V diskuzích mně můžete tykat.