ФорумПрограммированиеПыхнуть хотите?Готовые решения → Figaptcha

Figaptcha

  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Май 6, 2012, 1:10 п.п.

    Выношу на ваш суд каптчу "узнай картинку". Использует куку в формате HMAC и скрытое поле со случайным токеном. Сессия не требуется.


    <?php

    const KEY = 'Some random string';
    const NUM_FIGURES = 3;
    const TIMEOUT = 300;
    const COOKIE_NAME = 'figaptcha';

    class Figaptcha
    {
    protected $_key, $_timeout;

    function __construct($key, $timeout)
    {
    $this->_key = $key;
    $this->_timeout = $timeout;
    }

    function build($token, $data)
    {
    $expire = strval(time() + $this->_timeout);
    $x = serialize($data) . '|' . $expire;
    return strval($token) . '|' . $expire . '|' . hash_hmac('md5', $x, $this->_key);
    }

    function check($token, $data, $figaptcha)
    {
    if (!is_string($figaptcha)
    || !preg_match('%^([^|]+)\|([0-9]+)\|([0-9a-f]+)$%', $figaptcha, $matches)
    || $matches[1] != strval($token)
    || intval($matches[2]) < time()
    ) return FALSE;
    $x = serialize($data) . '|' . $matches[2];
    return hash_hmac('md5', $x, $this->_key) == $matches[3];
    }
    }

    $selfRef = $_SERVER['PHP_SELF'];
    $figaptcha = new Figaptcha(KEY, TIMEOUT);

    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (!isset($_COOKIE[COOKIE_NAME])
    || !isset($_POST['token'])
    || !isset($_POST['capcase'])
    || !$figaptcha->check($_POST['token'], array_keys($_POST['capcase']), $_COOKIE[COOKIE_NAME])) {
    $message = 'U\'R FCKIN\' BOT!!!';
    } else {
    die('All right! <a href="'.$selfRef.'">Try again</a>');
    }
    }

    $items = array();
    for ($i = 0; $i < NUM_FIGURES; ++$i) {
    $items[] = array(mt_rand(0, 3), mt_rand(0, 3));
    }

    $some = $items[mt_rand(0, NUM_FIGURES - 1)];
    $rightAnswer = array();
    foreach ($items as $i => $item) {
    if ($item == $some)
    $rightAnswer[] = $i;
    }

    $colours = array('red', 'blue', 'yellow', 'grey');
    $figures = array('circle', 'triangle', 'square', 'cross');
    $hint = $colours[$some[0]] . ' ' . $figures[$some[1]];

    $token = mt_rand(1, 1000000);

    $cookieValue = $figaptcha->build($token, $rightAnswer);
    setcookie(COOKIE_NAME, $cookieValue, 0, '/', '', FALSE, TRUE);

    ?>
    <!DOCTYPE HTML>
    <html>
    <head>
    <style type="text/css">
    #message {width: 300px; padding: .5em; border: 2px solid red;}
    #figaptcha {position: relative; overflow: hidden;}
    #figaptcha .item {float: left; text-align: center;}
    #figaptcha .answer {display: block; width: 100px; height: 100px; background: url('figures2.png');}
    </style>
    </head>
    <body>
    <?php if (isset($message)): ?><p id="message"><?php echo $message ?></p><?php endif; ?>
    <form action="<?php echo $selfRef ?>" method="post">
    <input type="hidden" name="token" value="<?php echo $token ?>" />
    <p>Check ALL figures wich are <strong><?php echo $hint ?></strong></p>
    <div id="figaptcha">
    <?php
    foreach ($items as $i => $item) {
    list($colour, $figure) = $item;
    $x = (-$colour * 100) + (400 * mt_rand(-10, 10));
    $y = (-$figure * 100) + (400 * mt_rand(-10, 10));

    ?>
    <label class="item"><input name="capcase[<?php echo $i ?>]" type="checkbox"/><br /><span class="answer" style="background-position: <?php echo $x ?>px <?php echo $y ?>px"></span></label>
    <?php
    }
    ?>
    </div>
    <input type="submit" name="submit" value="Post" />
    </form>
    </body>

    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Май 6, 2012, 1:51 п.п., спустя 40 минут 44 секунды

    Без труда и без изменения класса переделывается в каптчу "секретные вопросы":
    ιιlllιlllι унц-унц
  • kostyl

    Сообщения: 5210 Репутация: N Группа: Джедаи

    Spritz Май 6, 2012, 2:14 п.п., спустя 23 минуты 39 секунд

    круто!
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Май 6, 2012, 2:46 п.п., спустя 31 минуту 22 секунды

    грубая лесть! некруто, просто нормально. и пока она не распостраненная, боты под нее не заточятся )))
    ιιlllιlllι унц-унц
  • kostyl

    Сообщения: 5210 Репутация: N Группа: Джедаи

    Spritz Май 6, 2012, 4:12 п.п., спустя 1 час 26 минут 32 секунды

    грубая лесть!

    почему грубая лесть, просто не круто раз на то пошло
  • stopkran

    Сообщения: 53 Репутация: N Группа: Кто попало

    Spritz Май 6, 2012, 4:14 п.п., спустя 1 минуту 22 секунды

    Не, не круто! :-) Мало вариантов. И сложно придумать новые (фигуры или цвета) так, чтобы пользователь однозначно понял, о чём спрашивают.
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Май 6, 2012, 4:51 п.п., спустя 36 минут 46 секунд

    да, в версии с цветными фигурками вариантов немного. но сложность раскрытия зависит больше от других факторов. есть у меня сайтик куда боты прут как мухи на мед. сейчас там рекаптча и её боты обходят. я попробую эту штуку и доложу смогли ли боты приспособиться )))

    ιιlllιlllι унц-унц
  • Givi

    Сообщения: 2284 Репутация: N Группа: Адекваты

    Spritz Май 6, 2012, 4:59 п.п., спустя 8 минут 38 секунд

    artoodetoo, с картинками обойти не проблема по сути, ибо цвета. А вот с вопросами, тот тут для бота уже сложнее, потому в целом отличный вариант каптчи. Ну и, главное, не нужно глаз ломать чтоб разглядеть корявые буквы на цвето-мельтишащем фоне, как частенько бывает у сайтов. Главное вопросы придумать и легкоотвечаемые, но в то же время сложные для бота.
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Май 6, 2012, 5:06 п.п., спустя 6 минут 42 секунды

    вот простой способ усиления стойкости каптчи: ввести минимальное время, которое нужно человеку чтобы заполнить форму. зависит от количества полей и от того насколько сложные поля. допустим мы решаем, что реальный человек потратит никак не меньше 5 сек.

    <?php

    const KEY = 'Some random string';
    const NUM_FIGURES = 3;
    const MIN_TIMEOUT = 5;
    const MAX_TIMEOUT = 300;
    const COOKIE_NAME = 'figaptcha';
    // …
    function __construct($key, $timeoutMin, $timeoutMax)
    {
    $this->_key = $key;
    $this->_timeoutMin = $timeoutMin;
    $this->_timeoutMax = $timeoutMax;
    }
    // …
    function check($token, $data, $figaptcha)
    {
    if (!is_string($figaptcha)
    || !preg_match('%^([^|]+)\|([0-9]+)\|([0-9a-f]+)$%', $figaptcha, $matches)
    || $matches[1] != strval($token)
    || intval($matches[2]) < time()
    || intval($matches[2]) > time() + $this->_timeoutMax - $this->_timeoutMin
    ) return FALSE;
    $x = serialize($data) . '|' . $matches[2];
    return hash_hmac('md5', $x, $this->_key) == $matches[3];
    }
    // …
    $figaptcha = new Figaptcha(KEY, MIN_TIMEOUT, MAX_TIMEOUT);


    что имеем:
    - бот должен представлять алгоритм, он должен понимать, что все чекбоскы это цель для перебора
    - фактически сгенерировать правильную куку не зная секретного ключа нереально. то есть бот должен прочесть настоящую куку и использовать её.
    - если бот будет быстро перебирать варианты, он обломается, т.к. каптча учитывает мин. таймаут
    - если бот будет тормозить, кука просто станет невалидной, т.к. есть макс. таймаут
    ιιlllιlllι унц-унц
  • stopkran

    Сообщения: 53 Репутация: N Группа: Кто попало

    Spritz Май 6, 2012, 5:09 п.п., спустя 3 минуты 28 секунд

    artoodetoo, если боты так уж прут, то не проще ли на js одно поле в форме сделать? У меня ни на одном сайте капчи нет, и лет 5 как ни одного бота.
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Май 6, 2012, 5:31 п.п., спустя 21 минуту 44 секунды

    stopkran, не зарекайся. насчет js я убежденный сторонник «graceful degradation» и считаю, что при обломе с js пользователь может потерять удобство, но не должен потерять возможность.
    и вообще кто сказал, что боты не могут использовать js?
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz Май 6, 2012, 5:43 п.п., спустя 11 минут 56 секунд

    if (!is_string($figaptcha)
    || !preg_match('%^([^|]+)\|([0-9]+)\|([0-9a-f]+)$%', $figaptcha, $matches)
    || $matches[1] != strval($token)
    || intval($matches[2]) < time()
    || intval($matches[2]) > time() + $this->_timeoutMax - $this->_timeoutMin
    ) return FALSE;

    заюзай уже sprintf + sscanf :)
    Спустя 73 сек.
    и вообще кто сказал, что боты не могут использовать js?

    какой нить xrumer, так на иешке работает, там все есть - и ксс1.0(:D) и JS
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Май 6, 2012, 6:03 п.п., спустя 19 минут 52 секунды


    заюзай уже sprintf + sscanf :)

    это как, чото невкуриваю?
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz Май 6, 2012, 6:05 п.п., спустя 2 минуты 32 секунды

    artoodetoo, ну ты создаешь форматированную строку, и потом можешь разобрать ее назад чрез sscanf, а то так уебищно выглядит preg_match + условия в одной каше, прямо аж тошнит)
    Спустя 41 сек.
    во я нудный стал, делай чо хочешь :)
    Спустя 7 сек.
    старею
    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Май 7, 2012, 1:25 п.п., спустя 19 часов 19 минут 22 секунды

    Поколдовал со стилями и количеством вариантов.

    Как это выглядит в браузере:


    Как это выглядит без стилей, т.е. для не шибко умного бота:


    2^16 комбинаций. общее количество строк, включая фейковые, задается настройкой

    я охуенен
    ιιlllιlllι унц-унц

Пожалуйста, авторизуйтесь, чтобы написать комментарий!