Быстрый лёгкий надёжный форумный движок
Вы не вошли.
Страницы 1
Тема закрыта
Чтобы понять, что функция 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>
прошу высказываться
Вообщето сессии в punbb не используются, по крайней мере в 1.2.14 (кроме каптчи). Поэтому использовать для атаки незакрытую сессию невозможно в принципе. Использование дополнительного ключа в online, конечно дополнит защиту и поиметь клиента через ложную ссылку с нужной формой в нулевом фрейме из-за дырявого мода уже будет трудно. Дополнить защиту можно было бы опциональным выбором отслеживания ип, или списка адресов, чтобы злоумышленник не смог авторизоваться на угнанных куках.
hcs, все таки что скажешь по данной теме, то есть по контролю referer?
еще интересно почему в чистом punbb не пользуют session - ни в 1.2.14, ни в 1.3. наверное действуют по принципу "если можешь обойтись без чего-то, обходись".
У меня сейчас нет внешки, поэтому не могу пройти по твоим ссылкам и ознакомиться. Выложи сюда
Вобщем-то наш форум уже был пару раз под угрозой, в одном из случаев злоумышленники могли получать доступ к кукам пользователей. Этого уже достаточно было для получения контроля над профилями. И confirm_referer тут никак не мог помешать. В случае с csrf_token - тоже никак мешало бы планам злоумышленников. Т.е. этого недостаточно, для надежности требуется контроль IP-адреса. Если исходить не из кражи куков, то вполне здравый вариант, тем более что его давно уже обсуждали. Думаю, его надо брать на вооружение.
теория ничего не стоит без эксперимента тестирую 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 в одной сессии. но это выходит за рамки моей функции и этой темы.
Вообщето сессии в 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. Так мы сможем гарантировать, что данные из формы пришли из правильного места и правильного пользователя. Ну, по крайней мере, мы усложним задачу для хакера
Чтобы подсунуть данные ему надо будет поделать 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 нужен в любом раскладе.
Процедуру проверки еще не писал. Думаю.
Параллельно родилась идея как выводить список "кто еще сейчас читает эту тему"! Если мы будем сохранять в online.csrf_token хеш-ключи от посещенных URL, то нетрудно получить список всех активных пользователей с таким же ключом, как у текущего пользователя
кто еще сейчас читает эту тему"! Если мы будем сохранять в 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
да? или это пока ещё недоделанная функция?
очень сырой тест. если доделать, то да, решит проблему "referrer с ЧПУ".
предлагаю сделать это самому:)
1. добавить буковку confirm_referrer
2. если форум не в корне сайта, а например в /forum/, надо это учесть
(функция compose_ref должна обрезать $_SERVER['SCRIPT_NAME'])
3. в тех скриптах, которые контролируются, добавить поле ref по образцу из примера
4. если устраивает использование $_SESSION - то какбы готово, если нет - колдовать с таблицей online
спасибо. поёду ка я всётаки, куплю себе учебник по ПХП. давно пора было это сделать.
совета хочу - покупать по версии 4, или 5? ато там уже ПХП 6 продается. а на хочтинге - 4.4.3 ...
imho, лучше 5
про confirm_referrer см. также: http://punbb-pe.org.ru/viewtopic.php?id=55
в $key можно добавить IP (прям в хеш)
тогда на уровне безопасности +1
Не только с той же страницы, теми же куками, но и с тем же IP. При ограничении по времени - IP врядли будет меняться так быстро что бы не успеть заполнить форму.
Страницы 1
Тема закрыта