Русское сообщество fluxbb

Быстрый лёгкий надёжный форумный движок

Вы не вошли.

Объявление

Вы можете внести свой вклад в содержание сайта. Жертвователи попадут в почетную группу "Спонсоры". Поддержать сайт.

#1 2007-03-11 22:44:50

artoodetoo
Гость

требуется замена confirm_referer()

Чтобы понять, что функция confirm_referer PunBB 1.2.14 является очень хилой "защитой" не надо быть большим специалистом.

Есть по-крайней мере два железных аргумента чтобы переделать ее или полностью отказаться в пользу других проверок.
- Атака CSRF (см. Cross-Site Request Forgery и CSRF/XSRF FAQ). Злоумышленник может воспользоваться формой от вашего имени, пока сессия не закрыта.
(update: ему все-таки придется подделать http_referer)
- Непригодность при использовании ЧПУ, т.к. HTTP_REFERER будет другим, но при этом должен работать и старый вариант.

В первой ссылке есть пример как усилить защиту форм через добавление специального постоянно меняющегося ключа в параметры сессии. Он же вставляется в скрытые поля форм, затем одно сравнивается с другим $_POST['token'] == $_SESSION['token']).
Якобы на сегодняшний день это самый распостраненный способ защиты от атаки от чужого имени.

Но во втором источнике сказано, что такая защита будет работать если у вас (как у потенциальной жертвы) браузер с самыми новыми патчами и  все дыры в плагинах закрыты. На сегодняшний день дыры очень даже возможны в Acrobat и Flash плагинах. Через них злодеи могут добраться до параметров вашей сессии и тогда все насмарку. Не очень понятно, но надо быть начеку!

Что делают разработчики PunBB в этом плане? В текущей developer версии 1.3 уже нет функции confirm_referer. Вместо этого используется проверка на изменяющийся ключик с именем csrf_token. Этот ключик записывается в параметры соединения, но не через механизм сессий PHP, а в таблице online. (update: см. ниже - ключик не меняется)

Рекомендую к изучению:
- текущие билды PunBB 1.3 http://dev.punbb.org/browser/branches/punbb-1.3-dev
- сессии - правильное использование http://php.spb.ru/session.html
статья хорошая, но устарел синтаксис. сейчас рекомендуется использовать $_SESSION

Добавлено спустя   1 час   22 минуты   37 секунд:
вот набросал такую тестовую штучку. вызов confirm_referer() делается как и прежде, но теперь проверка усиливается через скрытое поле в форме и параметр сессии.
Теперь ЧПУ не помешает, атака тоже не должна пройти.
файл test.php:

<?php
session_start();

// I immitate PunBB environment. Put YOUR forum root into this string:
$pun_config['o_base_url'] = 'http://mypunbb.ru';
$lang_common['Bad referrer'] = 'Bad HTTP_REFERER. You were referred to this page from an unauthorized source. If the problem persists please make sure that \'Base URL\' is correctly set in Admin/Options and that you are visiting the forum by navigating to that URL. More information regarding the referrer check can be found in the PunBB documentation.';

function unescape($str)
{
    return (get_magic_quotes_gpc() == 1) ? stripslashes($str) : $str;
}

function message($s)
{
    die($s);
}

function compose_ref()
{
    global $pun_config;

    $ref = md5(uniqid(rand(), TRUE));
    $key = md5(str_replace('www.', '', $pun_config['o_base_url']).$_SERVER['SCRIPT_NAME']);
    $_SESSION[$key] = $ref . ':' . time();
    return $ref;
}

//
// New version of confirm_referer()
// Do not avoid SEF URLs and CSRF attacks!
//
function confirm_referer($script)
{
    global $pun_config, $lang_common;

    // HTTP_REFERER is the same domain
    if (!preg_match('#^'.preg_quote(str_replace('www.', '', $pun_config['o_base_url']), '#').'#i', str_replace('www.', '', (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''))))
        message($lang_common['Bad referrer']);

    $key = md5(str_replace('www.', '', $pun_config['o_base_url']).'/'.$script);
    // there are secret field and page was visited in this session
    if (!isset($_POST['ref']) || !isset($_SESSION[$key]))
        message($lang_common['Bad referrer']);

    list($ref, $time) = explode(':', $_SESSION[$key]);
    // secret field is valid and time is not over (5 minutes)
    if ($_POST['ref'] != $ref || time() - $time > 300)
        message($lang_common['Bad referrer']);
}

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test of new confirm_referer</title>
</head>
<body>
<h1>Test of new confirm_referer()</h1>
<?php

  if (isset($_POST['in']))
  {
    confirm_referer('test.php');

    $in = unescape($_POST['in']);
    echo 'OK. Your text is: "'.htmlspecialchars($in).'"<br /><br />'."\n";
  }
  else
    $in = '';
?>

<form action="test.php" method="post">
    <input type="hidden" name="ref" value="<?php echo compose_ref() ?>" />
    <input type="text" name="in" value="<?php echo htmlspecialchars($in) ?>" />
    <input type="submit" value="OK" />
</form>

</html>

прошу высказываться

#2 2007-03-12 08:54:01

hcs
Гость

Re: требуется замена confirm_referer()

Вообщето сессии в punbb не используются, по крайней мере в 1.2.14 (кроме каптчи). Поэтому использовать для атаки незакрытую сессию невозможно в принципе. Использование дополнительного ключа в online, конечно дополнит защиту и поиметь клиента через ложную ссылку с нужной формой в  нулевом фрейме из-за дырявого мода уже будет трудно. Дополнить защиту можно было бы опциональным выбором отслеживания ип, или списка адресов, чтобы злоумышленник не смог авторизоваться на угнанных куках.

#3 2007-03-12 09:51:05

artoodetoo
Гость

Re: требуется замена confirm_referer()

hcs, все таки что скажешь по данной теме, то есть по контролю referer?

еще интересно почему в чистом punbb не пользуют session - ни в 1.2.14, ни в 1.3. наверное действуют по принципу "если можешь обойтись без чего-то, обходись".

#4 2007-03-12 10:40:26

hcs
Гость

Re: требуется замена confirm_referer()

У меня сейчас нет внешки, поэтому не могу пройти по твоим ссылкам и ознакомиться. Выложи сюда smile
Вобщем-то наш форум уже был пару раз под угрозой, в одном из случаев злоумышленники могли получать доступ к кукам пользователей. Этого уже достаточно было для получения контроля над профилями. И confirm_referer тут никак не мог  помешать.  В случае с csrf_token - тоже никак мешало бы планам злоумышленников. Т.е. этого недостаточно, для надежности требуется контроль IP-адреса. Если исходить не из кражи куков, то вполне здравый вариант, тем более что его давно уже обсуждали. Думаю,  его надо брать на вооружение.

#5 2007-03-12 11:38:29

artoodetoo
Гость

Re: требуется замена confirm_referer()

теория ничего не стоит без эксперимента sad тестирую csrf_token

я поставил на локальный комп punbb 1.3 revision 916. там присутствует контроль через online.csrf_token.
зашел в админку, сохранил страничку на диск, затем еще погулял туда-сюда, потом загрузил с диска сохраненную страничку (file://... - это вам не http://... -- это и есть CSRF-атака ) и запостил изменения. все прокатило без ошибок. я представлял себе все немного иначе! оказывается csrf_token генерируется один раз на сессию  - это несколько иной уровень защиты.
получается csrf_token работает как session_id, только хуже.
если злоумышленник сумел воспользоваться XSS-дыркой и прочел поля из формы на стороне пользователя (на javascript), то он будет безнаказанно фигачить любые данные от вашего имени до тех пор, пока вы не создадите новую запись в online, то есть пока не заведете новую сессию.
не будет даже того слабенького confirm_referer() который есть в 1.2.14 !!!

в моем тесте с альтернативным confirm_referer() нагадить будет посложнее. ref постоянно генерится новый, есть контроль timeout, проверяется домен в http_referer - в комлексе это дает бОльшую защиту, хотя и не абсолютную.

P.S. по-настоящему хорошая защита должна включать запрет на разные IP в одной сессии. но это выходит за рамки моей функции и этой темы.

#6 2007-03-14 11:02:58

artoodetoo
Гость

Re: требуется замена confirm_referer()

hcs пишет:

Вообщето сессии в punbb не используются, по крайней мере в 1.2.14 (кроме каптчи). Поэтому использовать для атаки незакрытую сессию невозможно в принципе.

Вопрос терминологии. Сессия есть всегда, контролировать ее можно поразному. В PunBB не используются PHP-сессии. Я думаю от того, что синтаксис  зависит от версии PHP. Вместо этого они используют некий аналог с таблицей online.
update: Smatrys сказал, что на коллективных хостингах при некоторых конфигурация Apache временные файлы сессий уязвимы

Параллельная тема для англоговорящих на PunRes http://www.punres.org/viewtopic.php?id=3096
Как и здесь тема уползла в сторону безопасности в 1.3. Авторитеты не согласны со мной про уязвимость csrf_token в 1.3 Я провел эксперимент с кражей токена через javascript. Дублировать не буду - можете посмотреть там.

Думаю хорошая защита должна быть многослойной. Даже если будет найдена брешь в одном месте, нелегальный доступ блокируется другим способом.

Вот какие соображения:
Возьмем за основу online.csrf_token. Фактически некое подобие session_id. Добавим в ту же таблицу online поле "IP адрес пользователя в момент открытия сессии". Будем генерировать новый token при каждом посещении страницы и будем сохранять время посещения (как в моем примере). Для этого придется сделать csrf_token типа TEXT — сохраняем в него по одной строке на каждый посещенный URL. Так мы сможем гарантировать, что данные из формы пришли из правильного места и правильного пользователя. Ну, по крайней мере, мы усложним задачу для хакера smile
Чтобы подсунуть данные ему надо будет поделать referer, украсть token и успеть быстро его использовать, зайти с того же IP, что и настоящий пользователь.

Примерная структура online:
CREATE TABLE online (
user_id INT(10) UNSIGNED NOT NULL DEFAULT 1,
ident VARCHAR(200) NOT NULL DEFAULT '',
logged INT(10) UNSIGNED NOT NULL DEFAULT 0,
idle TINYINT(1) NOT NULL DEFAULT 0,
csrf_token TEXT,
ip VARCHAR(200) NOT NULL DEFAULT ''

);

Сейчас в поле ident записывается для залогиненых имя пользователя, для геста - IP. Думаю IP нужен в любом раскладе.
Процедуру проверки еще не писал. Думаю. smile

Параллельно родилась идея как выводить список "кто еще сейчас читает эту тему"! Если мы будем сохранять в online.csrf_token хеш-ключи от посещенных URL, то нетрудно получить список всех активных пользователей с таким же ключом, как у текущего пользователя smile

#7 2007-05-01 08:54:53

niikto
Гость

Re: требуется замена confirm_referer()

кто еще сейчас читает эту тему"! Если мы будем сохранять в online.csrf_token хеш-ключи от посещенных URL, то нетрудно получить список всех активных пользователей с таким же ключом, как у текущего пользователя

хотелось бы!

прочитал всю тему 3 раза. не понял - если я заменю старую функцию на это:

unction confirm_referer($script)
{
    global $pun_config, $lang_common;

    // HTTP_REFERER is the same domain
    if (!preg_match('#^'.preg_quote(str_replace('www.', '', $pun_config['o_base_url']), '#').'#i', str_replace('www.', '', (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''))))
        message($lang_common['Bad referrer']);

    $key = md5(str_replace('www.', '', $pun_config['o_base_url']).'/'.$script);
    // there are secret field and page was visited in this session
    if (!isset($_POST['ref']) || !isset($_SESSION[$key]))
        message($lang_common['Bad referrer']);

    list($ref, $time) = explode(':', $_SESSION[$key]);
    // secret field is valid and time is not over (5 minutes)
    if ($_POST['ref'] != $ref || time() - $time > 300)
        message($lang_common['Bad referrer']);
}

то вот эта проблема: "Суперкатегории"
у меня решится?
(ну добавлю там, поля в таб.online

да? или это пока ещё недоделанная функция?

#8 2007-05-01 19:32:36

artoodetoo
Гость

Re: требуется замена confirm_referer()

очень сырой тест. если доделать, то да, решит проблему "referrer с ЧПУ".
предлагаю сделать это самому:)

1. добавить буковку confirm_referrer smile
2. если форум не в корне сайта, а например в /forum/, надо это учесть
(функция compose_ref должна обрезать $_SERVER['SCRIPT_NAME'])
3. в тех скриптах, которые контролируются, добавить поле ref по образцу из примера
4. если устраивает использование $_SESSION - то какбы готово, если нет - колдовать с таблицей online

#9 2007-05-02 05:10:50

niikto
Гость

Re: требуется замена confirm_referer()

спасибо. поёду ка я всётаки, куплю себе учебник по ПХП. давно пора было это сделать.
совета хочу - покупать по версии 4, или 5? ато там уже ПХП 6 продается. а на хочтинге - 4.4.3 ...

#10 2007-05-02 07:03:02

artoodetoo
Гость

Re: требуется замена confirm_referer()

imho, лучше 5

#11 2008-01-21 22:55:12

artoodetoo
Гость

Re: требуется замена confirm_referer()

про confirm_referrer см. также: http://punbb-pe.org.ru/viewtopic.php?id=55

#12 2008-01-22 03:15:30

trijin
Гость

Re: требуется замена confirm_referer()

в $key можно добавить IP (прям в хеш)
тогда на уровне безопасности +1
Не только с той же страницы, теми же куками, но и с тем же IP. При ограничении по времени - IP врядли будет меняться так быстро что бы не успеть заполнить форму.

Подвал доски

Под управлением FluxBB. Хостинг Hostens