Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> [Klasa] Antibot - przyjazna ochrona przed botami, Zamiennik dla captcha. Moduł przeznaczony dla Kohana.
phpion
post
Post #1





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Witam,
dziś napisałem prosty mechanizm ochrony przed spamującymi botami.

Demo modułu można zobaczyć tutaj:
http://kohana.phpworkstation.com/antibottest

Paczuszkę z niezbędnymi plikami oraz przykładem wykorzystania można pobrać stąd:
http://kohana.phpworkstation.com/download/antibot.zip

Oto pliki wchodzące w skład modułu:

modules/antibot/config/antibot.php
  1. <?php
  2. $config = array(
  3.    /**
  4.      * Tajny klucz służący do zakodowania nazw plików graficznych.
  5.      */
  6.    'security_key' => 'mójmegatajnyklucz',
  7.  
  8.    /**
  9.      * Nazwa katalogu / ścieżka katalogu z plikami graficznymi.
  10.      */
  11.    'images_directory' => 'img/antibot',
  12.    'randoms' => array(
  13.        /**
  14.          * Liczba losowanych poprawnych elementów.
  15.          */
  16.        'good' => 2,
  17.  
  18.        /**
  19.          * Liczba losowanych niepoprawnych elementów.
  20.          */
  21.        'bad' => 3
  22.    ),
  23.    'images' => array(
  24.        /**
  25.          * Tablica nazw poprawnych plików graficznych.
  26.          */
  27.        'good' => array(
  28.            '1.jpg',
  29.            '2.jpg',
  30.            '3.jpg',
  31.            '4.jpg',
  32.            '5.jpg'
  33.        ),
  34.  
  35.        /**
  36.          * Tablica nazw niepoprawnych plików graficznych.
  37.          */
  38.        'bad' => array(
  39.            '10.jpg',
  40.            '20.jpg',
  41.            '30.jpg',
  42.            '40.jpg',
  43.            '50.jpg'
  44.        ),
  45.    )
  46. );
  47. ?>


modules/antibot/libraries/Antibot.php
  1. <?php
  2. /**
  3.  * Klasa tworząca przyjazne zabezpieczenie formularzy przed atakami botów.
  4.  *
  5.  * Działanie klasy polega na wyświetleniu określonej liczby plików graficznych,
  6.  * wśród których znajduje się pewna liczba elementów, które należy zaznaczyć w formularzu.
  7.  *
  8.  * @author phpion
  9.  */
  10. class Antibot {
  11.    /**
  12.      * Losowy ciąg znaków wykorzystywany przy kodowaniu nazwy pliku graficznego.
  13.      *
  14.      * @var string
  15.      */
  16.    private $token = '';
  17.  
  18.    /**
  19.      * Tajny klucz bezpieczeństwa wykorzystywany przy kodowaniu nazwy pliku graficznego.
  20.      *
  21.      * @var string
  22.      */
  23.    private $security_key = '';
  24.  
  25.    /**
  26.      * Nazwa katalogu / ścieżka katalogu, w którym znajdują się pliki graficzne.
  27.      *
  28.      * @var string
  29.      */
  30.    private $images_directory = '';
  31.  
  32.    /**
  33.      * Tablica zawierająca informację o ilości losowanych plików graficznych z rozróżnieniem na typ (dobry/zły).
  34.      *
  35.      * $array = array(
  36.      *        'good' => 2,
  37.      *        'bad'  => 3
  38.      * );
  39.      *
  40.      * @var array
  41.      */
  42.    private $randoms = array();
  43.  
  44.    /**
  45.      * Tablica nazw plików graficznych służących do wyświetlania dobrych/złych elementów.
  46.      *
  47.      * $array = array(
  48.      *        'good' => array(1, 2, 3),
  49.      *        'bad'  => array(10, 20, 30
  50.      * );
  51.      *
  52.      * @var <type> tablica
  53.      */
  54.    private $images = array();
  55.  
  56.    /**
  57.      * Konstruktor klasy Antibot.
  58.      *
  59.      * Automatycznie pobiera potrzebne dane z pliku konfiguracyjnego.
  60.      */
  61.    public function __construct() {
  62.        $config = Kohana::config('antibot');
  63.  
  64.        $this->security_key = (string)$config['security_key'];
  65.        $this->images_directory = (string)$config['images_directory'];
  66.        $this->randoms = (array)$config['randoms'];
  67.        $this->images = (array)$config['images'];
  68.  
  69.        $this->set_token();
  70.    }
  71.  
  72.    /**
  73.      * Losuje listę plików graficznych.
  74.      *
  75.      * @return array Tablica zakodowanych nazw plików graficznych.
  76.      */
  77.    public function get_images() {
  78.        $return = array();
  79.  
  80.        foreach (array(self::GOOD, self::BAD) as $type) {
  81.            shuffle($this->images[$type]);
  82.            $images = array_chunk($this->images[$type], (int)$this->randoms[$type]);
  83.  
  84.            $return = array_merge($return, $images[0]);
  85.        }
  86.  
  87.        shuffle($return);
  88.  
  89.        foreach ($return as $key => $item) {
  90.            $return[$key] = $this->encode_image($item);
  91.        }
  92.  
  93.        return $return;
  94.    }
  95.  
  96.    /**
  97.      * Koduje nazwę pliku graficznego.
  98.      *
  99.      * @param string $image Nazwa pliku graficznego.
  100.      * @return array Zakodowana nazwa pliku graficznego.
  101.      */
  102.    private function encode_image($image) {
  103.        $input = Input::instance();
  104.  
  105.        return md5($this->encode_token().$image.$input->ip_address().$this->security_key);
  106.    }
  107.  
  108.    /**
  109.      * Wyszukuje prawdziwą nazwę pliku graficznego na podstawie jego zakodowanej nazwy.
  110.      *
  111.      * @param string Zakodowana nazwa pliku graficznego.
  112.      * @return string|boolean Prawdziwa nazwa pliku graficznego jeśli zostanie znaleziony; w przeciwnym razie zwraca FALSE.
  113.      */
  114.    private function find_image($encoded_image) {
  115.        $images = array_merge($this->images[self::GOOD], $this->images[self::BAD]);
  116.  
  117.        foreach ($images as $image) {
  118.            if ($this->encode_image($image) === $encoded_image) {
  119.                return $image;
  120.            }
  121.        }
  122.  
  123.        return FALSE;
  124.    }
  125.  
  126.    /**
  127.      * Zwraca obiekt typu Image reprezentujący plik graficzny.
  128.      *
  129.      * @param string Zakodowana nazwa pliku graficznego.
  130.      * @return Image|boolean Obiekt typu Image jeśli znaleziono prawdziwy plik graficzny; w przeciwnym razie zwraca FALSE.
  131.      */
  132.    public function get_image($encoded_image) {
  133.        $decoded_image = $this->find_image($encoded_image);
  134.  
  135.        return $decoded_image ? new Image($_SERVER['DOCUMENT_ROOT'].Kohana::config('config.site_domain').$this->images_directory.'/'.$decoded_image) : FALSE;
  136.    }
  137.  
  138.    /**
  139.      * Koduje token.
  140.      *
  141.      * @return string Zakodowany token.
  142.      */
  143.    private function encode_token() {
  144.        $return = $this->token;
  145.        $return = strrev($return);
  146.        $return = md5($return);
  147.        $return = substr($return, 9, 14);
  148.        $return = md5($return);
  149.  
  150.        return $return;
  151.    }
  152.  
  153.    /**
  154.      * Sprawdza czy użytkownik wskazał poprawne elementy z przedstawionej mu listy.
  155.      *
  156.      * @param array $checked Tablica zaznaczonych elementów.
  157.      * @return boolean TRUE jeśli zaznaczono poprawne elementy; w przeciwnym razie zwraca FALSE.
  158.      */
  159.    public function validate(array $checked = array()) {
  160.        $checked = array_unique($checked);
  161.  
  162.        if (count($checked) === (int)$this->randoms[self::GOOD]) {
  163.            $correct = 0;
  164.  
  165.            foreach ($this->images[self::GOOD] as $item) {
  166.                if (in_array($this->encode_image($item), $checked)) {
  167.                    $correct++;
  168.                }
  169.            }
  170.  
  171.            return $correct === (int)$this->randoms[self::GOOD];
  172.        }
  173.  
  174.        return FALSE;
  175.    }
  176.  
  177.    /**
  178.      * Ustawia token dla instancji klasy.
  179.      *
  180.      * Jeżeli nie przekazano parametru $token wówczas nadawany jest losowy token.
  181.      *
  182.      * @param string|NULL $token Token.
  183.      */
  184.    public function set_token($token = NULL) {
  185.        if (is_null($token)) {
  186.            $token = md5(uniqid());
  187.        }
  188.  
  189.        $this->token = (string)$token;
  190.    }
  191.  
  192.    /**
  193.      * Zwraca token.
  194.      *
  195.      * @return string Token.
  196.      */
  197.    public function get_token() {
  198.        return $this->token;
  199.    }
  200.  
  201.    /**
  202.      * Nazwa klucza dla poprawnych elementów.
  203.      */
  204.    const GOOD = 'good';
  205.  
  206.    /**
  207.      * Nazwa klucza dla niepoprawnych elementów.
  208.      */
  209.    const BAD = 'bad';
  210. }
  211. ?>


modules/antibot/controllers/antibot.php
  1. <?php
  2. /**
  3.  * Kontroler odpowiedzialny za wyświetlanie odpowiedniego pliku graficznego.
  4.  */
  5. final class Antibot_Controller extends Controller {
  6.    /**
  7.      * Zwraca do przeglądarki konkretny plik graficzny.
  8.      */
  9.    public function render_image() {
  10.        $image = (string)$this->input->get('image', '');
  11.        $token = (string)$this->input->get('token', '');
  12.  
  13.        $ab = new Antibot();
  14.        $ab->set_token($token);
  15.  
  16.        $image = $ab->get_image($image);
  17.  
  18.        if ($image instanceof Image) {
  19.            echo $image->render();
  20.        }
  21.    }
  22. }
  23. ?>

Jeżeli macie jakiekolwiek uwagi czy sugestie to chętnie się z nimi zapoznam (IMG:http://forum.php.pl/style_emoticons/default/smile.gif)

Pozdrawiam,
pion
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 11)
wookieb
post
Post #2





Grupa: Moderatorzy
Postów: 8 989
Pomógł: 1550
Dołączył: 8.08.2008
Skąd: Słupsk/Gdańsk




A czy dobrze napisany graficzny token nie bedzie lepszy?
System wybierania obrazków jest troche duzy a mniejsze wersja moze byc nieuzyteczna (Chodzi mi o zajetosc na stronie)
Uwazam ze najlepszym systemem antybotowym jest odpowiadanie na proste pytania. Np jest tak w wyszukiwarce na flashzone.pl
Pytanie typu: Jakiego koloru jest śnieg.
Przy odpowiednio częstym zmienianiu pytań, żaden bot tego nie łyknie.
Go to the top of the page
+Quote Post
Riklaunim
post
Post #3





Grupa: Zarejestrowani
Postów: 640
Pomógł: 44
Dołączył: 8.02.2004

Ostrzeżenie: (0%)
-----


Ja tam stosuję tekstowe zabezpieczenie - podanie n-tej cyfry z podanej liczby. Automatyczne boty się na tym wysypują (IMG:http://forum.php.pl/style_emoticons/default/winksmiley.jpg)
Go to the top of the page
+Quote Post
pyro
post
Post #4





Grupa: Zarejestrowani
Postów: 2 148
Pomógł: 230
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Cytat(Riklaunim @ 14.05.2009, 22:45:14 ) *
Ja tam stosuję tekstowe zabezpieczenie - podanie n-tej cyfry z podanej liczby. Automatyczne boty się na tym wysypują (IMG:http://forum.php.pl/style_emoticons/default/winksmiley.jpg)


no zalezy jak to przedstawiasz uzytkownikowi... ja tam korzystam z captchy (klasa od google) i zabezpieczenie 100% skuteczne. @phpion, mi niestety pomysł nie wydaje się zbytnio użyteczny z powodów, które podał @wookieb. To troche proba wymyslenia czegos, co jest niepotrzebne (IMG:http://forum.php.pl/style_emoticons/default/winksmiley.jpg)
Go to the top of the page
+Quote Post
Crozin
post
Post #5





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Poza tym, nadal istnieje spora szansa na to, że bot złamie to - na zasadzie zaznaczania losowych checkboxów.
Go to the top of the page
+Quote Post
phpion
post
Post #6





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Cytat(wookieb @ 14.05.2009, 22:39:44 ) *
A czy dobrze napisany graficzny token nie bedzie lepszy?

Jak dla mnie captcha nie jest cudem wygody dla użytkownika końcowego stąd pomysł (w sumie gdzieś to już widziałem) o innym podejściu do zabezpieczenia.

Cytat(pyro @ 14.05.2009, 22:50:02 ) *
ja tam korzystam z captchy (klasa od google) i zabezpieczenie 100% skuteczne

j.w.

Cytat(Crozin @ 15.05.2009, 00:08:03 ) *
Poza tym, nadal istnieje spora szansa na to, że bot złamie to - na zasadzie zaznaczania losowych checkboxów.

Przy większej liczbie prawidłowych obrazków (np. 5 dobrych + 5 złych) szanse te są mniejsze. Poza tym wystarczy co jakiś czas zmienić ten stosunek i już (IMG:http://forum.php.pl/style_emoticons/default/smile.gif)

Tak czy siak dzięki za opinie.
Go to the top of the page
+Quote Post
Crozin
post
Post #7





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Cytat
Przy większej liczbie prawidłowych obrazków (np. 5 dobrych + 5 złych) szanse te są mniejsze. Poza tym wystarczy co jakiś czas zmienić ten stosunek i już
Jest 6:20 i musze lecieć na autobus więc liczyć nie będę, ale wystarczy, że jedna na 100 prób "na ślepo" się powiedzie i już trzeba się liczyć z dziesiątkami botów dziennie, które przejdą walidację.

A czytanie instrukcji + rozpoznawanie (nie)prawidłowych obrazków przez użytkownika wydaje mi się prawdę powiedziawszy nieco trudniejsze niż sama CAPTCHA.
Go to the top of the page
+Quote Post
nieraczek
post
Post #8





Grupa: Zarejestrowani
Postów: 405
Pomógł: 6
Dołączył: 12.01.2007

Ostrzeżenie: (0%)
-----


Captcha jest beznadziejna, zwykle tam gdzie to jest to rezygnuje z rejestracji, chyba że bardzo mi zależy na rejestracji na danej stronie. Z jakich powodów ? Zz takich powodów, że zwykle muszę wpisywać kilka razy kod z obrazka bo zawsze się mylę, np. nie jestem w stanie odróżnić litery O od cyfry 0, litery I od cyfry 1 itd. Może to i chroni przed spambotami, ale ja zwykle rezygnuję z rejestracji w takich serwisach, bo nie jestem w stanie rozczytać co tam jest nabazgrane.

Ten post edytował nieraczek 15.05.2009, 08:00:51
Go to the top of the page
+Quote Post
pyro
post
Post #9





Grupa: Zarejestrowani
Postów: 2 148
Pomógł: 230
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Cytat(nieraczek @ 15.05.2009, 09:00:06 ) *
Captcha jest beznadziejna, zwykle tam gdzie to jest to rezygnuje z rejestracji, chyba że bardzo mi zależy na rejestracji na danej stronie. Z jakich powodów ? Zz takich powodów, że zwykle muszę wpisywać kilka razy kod z obrazka bo zawsze się mylę, np. nie jestem w stanie odróżnić litery O od cyfry 0, litery I od cyfry 1 itd. Może to i chroni przed spambotami, ale ja zwykle rezygnuję z rejestracji w takich serwisach, bo nie jestem w stanie rozczytać co tam jest nabazgrane.


To sobie sciagnij captche od google, sa tam uzywane słowa a nie losowe litery
Go to the top of the page
+Quote Post
pijanyadmin
post
Post #10





Grupa: Zarejestrowani
Postów: 128
Pomógł: 1
Dołączył: 24.10.2007

Ostrzeżenie: (0%)
-----


Nie ma captche od google, jest tylko cpatcha podobna do tej z google.
Go to the top of the page
+Quote Post
pyro
post
Post #11





Grupa: Zarejestrowani
Postów: 2 148
Pomógł: 230
Dołączył: 26.03.2008

Ostrzeżenie: (0%)
-----


Cytat(pijanyadmin @ 15.05.2009, 13:23:17 ) *
Nie ma captche od google, jest tylko cpatcha podobna do tej z google.


Miałem to na myśli (IMG:http://forum.php.pl/style_emoticons/default/winksmiley.jpg)

link: http://code.google.com/p/cool-php-captcha
Go to the top of the page
+Quote Post
pijanyadmin
post
Post #12





Grupa: Zarejestrowani
Postów: 128
Pomógł: 1
Dołączył: 24.10.2007

Ostrzeżenie: (0%)
-----


Poza tym, nieraczek to Ty nie masz konta praktycznie nigdzie? (IMG:http://forum.php.pl/style_emoticons/default/biggrin.gif) Nawet emaila wp,gmail? To straszne... Poza tym nie widze problemu aby pisząc takie "bajery" wykluczyć znaki "o01l" itp. Przy stronie o cioci Krysi nie ma sensu pisać captcha, ale przy większych serwisach jest to wskazane.
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 25.08.2025 - 16:01