Author Topic: CSRF уязвимости. возможность перехватить доступ к системе  (Read 13440 times)

0 Members and 1 Guest are viewing this topic.

pl-m

  • Full Member
  • ***
  • Posts: 13
здраствуйте!

я установил версию 1.6.4 mibew... и обнаружил что POST-запросы с форм (на панеле администратора/оператора) -- не проверяются на CSRF

например, у меня получилось провести CSRF-атаку для /webim/operator/operators.php (подстановка другого email для восстановления пароля оператора номер 1)

это значит злоумышленник сможет проделать тоже самое, если сможет подсунуть жертве (жертва -- оператор) заранее подготовленную ссылку, воспроизводящую CSRF-атаку

этуже проблему я вкрадце продублировал тут -- https://github.com/inspirer/mibew/issues/8

спасибо за уделённое мне внимание! (и заранее спасибо если проблему будет решена :))

pl-m

  • Full Member
  • ***
  • Posts: 13
один из вариантов (простого, но не самого лучшего :) ) патча для исправления проблемы, вот -- https://gist.github.com/1298748#file_0001_created_function_csrf_check_referer.patch

MSK

  • Native
  • *****
  • Posts: 61
Тут видимо надо использовать не
$_SERVER['SERVER_NAME']
а
$_SERVER['HTTP_HOST']

поскольку первый может отдать доменное имя без "www"

pl-m

  • Full Member
  • ***
  • Posts: 13
идея с 'HTTP_HOST' мне нравится (ведь 'HTTP_HOST' и 'HTTP_REFERER' находятся на одном уровне по способу получения).. главное только помнить что 'HTTP_HOST' в некоторых случаях содержит только <Имя> а в некоторых <Имя:Порт> ('SERVER_NAME' как показала моя практика содержит имя без номера порта)

тоесть в случае с 'HTTP_HOST' -- наверно усложнение будет заключаться в следущей чуток-усложнённой проверке (вместо простой прошлой) :-) :
Code: [Select]
$http_referer_host = array_key_exists('host', $parsed_http_referer)?$parsed_http_referer['host']:'';
$http_referer_port = array_key_exists('port', $parsed_http_referer)?$parsed_http_referer['port']:'';
if($http_referer_host.':'.$http_referer_port != $_SERVER['HTTP_HOST'] &&
                    $http_referer_host != $_SERVER['HTTP_HOST'])
{
                @header('Content-Type: text/plain;charset=utf-8');
                die('Suspected to CSRF');
}
« Last Edit: October 20, 2011, 12:34:32 PM by pl-m »

MSK

  • Native
  • *****
  • Posts: 61
если нет $http_referer_port, то проверка
 
$http_referer_host.':'.$http_referer_port != $_SERVER['HTTP_HOST']

не пройдет, присутствует ":", которого нет в $_SERVER['HTTP_HOST']


pl-m

  • Full Member
  • ***
  • Posts: 13
да, запутался слегка :-D

...ну вот поэтому в самом начале и написал SERVER_NAME .. чтобы не путаться с этими портами и их отсутствиейм :-D

pl-m

  • Full Member
  • ***
  • Posts: 13
...но суть вся в следущем:

если два условия отсутствия_равенства ("!=") становятся TRUE -- то их результат умножения ("&&") тоже будет TRUE.. седовательно в этом случае выплеснется ошибка-и-смерть (die)

тоесть по закону де-моргана ( http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD%D1%8B_%D0%B4%D0%B5_%D0%9C%D0%BE%D1%80%D0%B3%D0%B0%D0%BD%D0%B0 ) -- следущие два выражения эквивалентны:
Code: [Select]
if ($check_referer_value != $valid_host && $check_referer_value != $valid_host_and_port) { die('Error'); }
else { /* CSRF нет, всё хорошо*/ }
и
Code: [Select]
if ($check_referer_value == $valid_host_and_port || $check_referer_value == $valid_host) { /* CSRF нет, всё хорошо*/ }
else { die('Error'); }

ну последнее выражение ясное дело надо записать как :-):
Code: [Select]
if (!($check_referer_value == $valid_host_and_port || $check_referer_value == $valid_host)) { die('Error'); }
....тоесть какое выражение прощще-для-понимания (и не запутывания) -- то можно и использовать.... но первое выражение (то где "!=") -- просто содержит меньше операторов :-)