CSRF и SSRF уязвимости в Битрикс
CSRF и SSRF атаки представляют серьезную угрозу безопасности веб-проектов. Они позволяют выполнять нежелательные действия от имени пользователя или сервера.
CSRF-атака
CSRF (Cross-Site Request Forgery) межсайтовая подделка запроса. При этой атаке пользователь выполняет нежелательные действия на доверенном сайте, где он уже авторизован.
Принцип CSRF-атаки
- Пользователь авторизуется на сайте,
cool-bank.com
- Браузер сохраняет cookie-файлы сессий
- Пользователя перенаправляют на вредоносный сайт,
evil.com
evil.com
отправляет скрытую форму наcool-bank.com
- Браузер пользователя автоматически добавляет
cookie
авторизации cool-bank.com
выполняет действие от имени пользователя
В примере используется форма, чтобы отправить запрос на перевод денег от имени пользователя:
<form action="https://cool-bank.com/sendmoney" method="POST">
<input type="hidden" name="sendmoney" value="1000">
</form>
Как защититься от CSRF
Существует два основных подхода, которые эффективно работают вместе: CSRF-токены
и SameSite cookie
.
CSRF-токены
CSRF-токен
это секретное и непредсказуемое значение, которое сервер генерирует и передает пользователю. Пользователь включает токен в каждый запрос с авторизацией. Сервер проверяет токен перед выполнением действия.
Bitrix Framework предоставляет функции для работы с токенами.
bitrix_sessid()
возвращает CSRF-токен. Он является идентификатором сессии:
// feb8414592f24d96f6fd0c656e6ccd67
echo bitrix_sessid();
bitrix_sessid_post()
вставляет токен в форму:
// <input type="hidden" name="sessid" id="sessid" value="1bd24e8b34e32f1dc9d9463cf591729a" />
echo bitrix_sessid_post();
bitrix_sessid_get()
возвращает строку вида $varname=идентификатор_сессии
для использования в GET параметрах, можно указать название параметра
// sessid=1bd24e8b34e32f1dc9d9463cf591729a
bitrix_sessid_get($varname='sessid')
check_bitrix_sessid()
проверяет, совпало ли значение bitrix_sessid
с $varname
из GET
параметра или заголовка X-Bitrix-Csrf-Token
:
check_bitrix_sessid($varname='sessid')
SameSite
SameSite
это дополнительный атрибут для cookie
. Он указывает браузеру, отправлять ли cookie
в межсайтовых или внутрисайтовых запросах. Это обеспечивает частичную защиту от CSRF
и других атак.
Безопасную cookie
можно сделать двумя способами:
setcookie('cookie_name', 'cookie_value', ['samesite' => 'Strict']);
$cookie = new Cookie("cookie_name", "cookie_value");
$cookie->setSameSite("Strict");
$context = Application::getInstance()->getContext();
$context->getResponse()->addCookie($cookie);
Атрибут SameSite
может принимать следующие значения:
None
ограничения на файлы cookie не устанавливаютсяStrict
cookie
отправляются только в рамках одного домена и не передаются при переходах между разными сайтамиLax
cookie
передаются только при безопасных HTTP-запросах в межсайтовых переходах, но блокируются для небезопасных методов и при загрузке вложенных ресурсов
Установка атрибута SameSite=Strict
для всех сookie
может ухудшить пользовательский опыт, особенно при межсайтовых переходах. Например, если пользователь авторизуется на сайте, а затем переходит по внешней ссылке, сookie
файлы не отправятся, и он окажется неавторизованным.
Атрибут SameSite=Lax
более гибкий вариант, но его можно обойти, например, через GET
запросы вместо POST
или клиентские перенаправления.
Выбор между Strict
и Lax
зависит от типа сайта:
Lax
подходит для интернет-магазинов, где важна удобная навигацияStrict
предпочтителен для банковских приложений, где безопасность в приоритете
SSRF-атака
SSRF
(Server-Side Request Forgery) подделка серверных запросов. Атака позволяет отправлять запросы от имени сервера.
$http = new HttpClient();
print_r($http->get($_GET['uri']));
В примере сервер напрямую обращается к произвольному адресу и выводит ответ на экран. Параметр uri
может быть использован для доступа к внутренним сервисам.
Почему это опасно
Представьте, что на сервере работает служба на порте 1337. Доступ к службе закрыт для внешнего мира. Однако, если удастся отправить запрос от имени сервера, можно получить доступ к службе. Это позволит сканировать внутреннюю сеть или выполнять произвольный код.
Как защититься от SSRF
Для защиты от SSRF-атак ограничьте возможность отправки запросов к внутренним ресурсам. Это можно сделать с помощью встроенных механизмов Bitrix Framework.
Ограничение доступа к частным IP
Используйте метод setPrivateIp(false)
в HTTP-клиенте, чтобы запретить запросы к частным адресам:
// создаем объект HTTP-клиента
$http = new HttpClient();
// запрещаем доступ к частным IP
$http->setPrivateIp(false);
// пытаемся отправить запрос
$http->get($_GET['uri']);
При попытке запроса к локальному адресу HTTP-клиент вернет ошибку.
Безопасная загрузка изображений
Используйте CFile::MakeFileArray()
для безопасной загрузки изображений с удаленных хостов. Метод проверяет файл на корректность и предотвращает загрузку вредоносных данных:
$file = CFile::MakeFileArray($_GET['uri']);
if ($file) {
$res = CFile::CheckImageFile($file);
if ($res === null) {
// Изображение корректно, можно продолжать
} else {
// Обработка ошибки
}
}