PHP — Введение в основы безопасности веб приложений 1

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

Этот пост расскажет о некоторых уязвимостях которые пораждает разработчик веб приложения. Обратите внимание, что этот список никоим образом не является полной гарантией того, что с вашим сайтом никогда не случится ничего плохого. Вы все равно должны самостоятельно исследовать и читать статьи и книги о безопасности приложений.

Также обратите внимание, что пример кода написан кратким и простым для понимания, насколько это возможно, и по этой причине может не соответствовать рекомендациям. Если вы Back-end разработчик, вам не только нужно хранить и обрабатывать пользовательские данные, но и обязательно нужно знать, как правильно их защитить.

SQL-инъекция

Это одна из самых серьёзных угроз для вашего сайта. Сайт уязвимый для SQL-инъекций означает что любой может сбросить вашу базу данных или сделать что-то еще хуже.

Если ваше приложение извлекает динамический контент из базы данных, это означает, что вам придется выполнять какой-то SQL. Давайте рассмотрим простой пример, подобный этому:

В этом примере атакующий контролирует запросы, отправленные через GET и POST. Здесь код ожидает, что обычное имя пользователя, например, ‘Вася Пупкин’, приведет к следующему запросу:

Так как запрос от пользователя ни как не фильтруется, злоумышленник может изменить параметр имени пользователя, чтобы он выглядел к примеру так: ‘OR’ 1 ‘=’ 1

Это приведет к запросу, который выглядит следующим образом:

И таким же образом он может слить всю вашу БД с паролями, данными и т.д

Как от этого защищаться?

Выполняйте обработку всего пользовательского ввода.

Например как это можно сделать используя  PDO:

Каждая часть динамических данных имеет префикс — двоеточие. После этого вы передаете все параметры в виде массива в функцию execute, остальное PDO сделает за вас.

Операторы «подготовки» данных поддерживаются практически всеми драйверами баз данных, используйте их! Когда вы привыкнит все свои запросы писать подобных образом, ваше приложение будет защищено от SQL  инъекций.

XSS

XSS чаще именуется как межсайтовый скриптинг.

Суть: Злоумышленник внедряет JavaScript на ваш сайт.

Есть два варианта XSS

1. Вредоносный сценарий передаётся через GET в строке запроса URL

2. Вредоносный сценарий хранится на вашем сервере.

XSS имеет место быть, когда вы неправильно экранируете пользовательский ввод, который выводится на HTML-странице. Возьмем, к примеру,  простую страницу поиска, которая выводит то что искал пользователь (первый вариант XSS):

Поскольку вы выводите на страницу то, что пользователь отправил —  злоумышленник может создать URL-адрес, который выглядит следующим образом:

Полученный документ теперь будет выглядеть так (появится окно с предупреждением):

Ну и что, мне какое дело что у пользователя будет на странице?

Javascript может:

Загрузка наборов эксплойтов, заражающих ваших пользователей вредоносным ПО

Украсть неправильно настроенные куки

Украсть учетные данные, подключив регистратор ключей к вашим формам входа

Украсть конфиденциальную информацию

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

Изменить оформление вашего сайта и замените все ваши изображения (например на фото Шрэка)

Как защищаться?

Некоторые браузеры предпринимают шаги что бы блокировать подобные «инсинуации» с JS кодом, но надежда на браузер не является способом защиты

Правильный способ защитить себя — избежать пользовательского ввода. Либо фильтровать его так:

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

XSRF / CSRF

CSRF, сокращение от «Подделка межсайтовых запросов» — это метод, используемый злоумышленниками для того, чтобы заставить ваших пользователей выполнять нежелательные действия в вашем приложении при входе в систему.

Допустим, у вас есть страница, которая позволяет пользователям удалять свою учетную запись следующим образом:

Злоумышленник может создать на своем сайте форму, которая запускает этот специальный через URL-адрес (это также работает с формами, использующими POST):

И в мгновение ока ваша учетная запись на сайте исчезла.

Защита от подобных атак немного сложнее, чем защита от XSS или SQL-injections.

Самый популярный способ защиты от этого — генерирование крипто-безопасной строки, называемой токеном CSRF, и сохранение её в куках или в сессии.

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

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

Обратите внимание, что это очень простой пример, и вы можете доработать его. Если вы используете PHP-фреймворк, такой как Symfony, для вас уже есть токен CSRF, который вы можете использовать.

LFI

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

Частым местом где эта ошибка может возникнуть, не продуманная маршрутизация приложения.

Возьмем пример, где приложение из GET запроса должно получить имя файла для подключения:

Всё просто, GET не пустой — подключаем то что в GET.

Поскольку include может загружать любой файл, а не только PHP-файлы, злоумышленник может передать любой файл в вашей файловой системе, например:

В итоге в браузере отобразится файл паролей.

Чтобы защититься от этой атаки, вы должны тщательно продумать какие шаблоны файлов раззрешать, так же не забывайте о потенциально опасных символах «.» «/» «\» из входной строки.

Если вы действительно хотите использовать такую ​​систему маршрутизации (хотя это не рекомендуется), вы можете автоматически добавлять расширение php самостоятельно, удалив любые символы, которые не являются [a-zA-Z0-9 \ — \ _ ] и загружать шаблоны из специальной папки шаблонов, чтобы избежать включения чего-либо другого кроме файла шаблона.

Лучше действуйте по правилу — запрещено всё, кроме явно заданных файлов, так же перед подключением файла дописывайте к нему свой путь и проверяйте существует ли он перед подключением.

 

Недостаточное хеширование пароля

Почти все веб-приложения должны хранить пароли пользователей в процессе своей работы.

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

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

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

В следующем примере используется MD5. Никода не используйте MD5 — он давно и успешно взламывается.

Предположим, что user1 имеет супер-безопасный пароль «ilovecats123», user315 имеет такой же пароль. Это приводит к тому, что оба пользователя имеют один и тот же хэш в своей строке базы данных: 5e2b4d823db9d044ecd5e084b6d33ea5

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

На данный момент одним из лучших вариантов хеширования паролей является bcrypt. Он разработан для паролей и имеет настройки.

В новых версия PHP есть функция password_hash, которая выполняет всю работу за вас. Вам даже не нужно генерировать соль, функция делает это за вас! Так же в PHP есть функция password_verify, которая может проверять действительность пароля пользователя.

Вот пример того, как их использовать:

Также обратите внимание, что хеширование — это не то же самое, что шифрование. Если вы что-то хэшируете, вы теряете информацию  и данные находящиеся в хэше.

Шифрование сохраняет исходную информацию в «зашифрованном» формате, и ее можно восстановить, если вы знаете ключ шифрования.

MITM

MITM (человек посередине) — это не прямая атака на вашу систему, а атака, направленная против ваших пользователей. Злоумышленник перехватывает трафик между вашим сайтом и пользователем и внедряет вредоносный контент или читает конфиденциальную информацию. Обычно это происходит в общественных сетях WiFi, хотя это также может происходить в любом другом месте, через которое проходит трафик.

Единственная защита от этого — использовать HTTPS. С HTTPS ваше соединение будет зашифровано, и трафик не может быть прочитан или подделан. Вы можете получить бесплатный SSL-сертификат от Let’s Encrypt.

Однако есть ряд вещей,которые помогут защитить HTTPS сайт ещё лучше. Первое — это отправлять заголовок Strict-Transport-Security . Этот заголовок сообщает браузеру, что ваш сайт всегда будет обслуживаться по HTTPS, если ваш сайт не обслуживается по HTTPS, что-то пошло не так и браузер не должен отображать страницу.

Однако есть одна очевидная проблема. Если браузер никогда не видел ваш сайт раньше, он не знает что вы хотите от него этим заголовком, к счатью для этого есть ресурс hstspreload.org.

Вы можете зарегистрировать свой сайт здесь: https://hstspreload.org/

После регистрации сайт будет помечен как работающий только по протоколу HTTPS и будет добавлен в исходный код Google Chrome, Firefox, Opera, Safari, IE11 и Edge.

Инъекция в консоль сервера

Это пожалуй худшее что может случиться с вашим приложением. Цель внедрения команд — заставить ваш сервер выполнять произвольные команды оболочки.

Вы можете столкнуться с этой атакой если будете использовать функцию shell_exec или exec.

Вот не большой пример с командой ping:

Вывод будет содержать 5 попыток проверки связи с целевым хостом. Таким образом можно выполнить всё что угодно на сервер.

К счастью, php предлагает функцию для экранирования параметров оболочки.

escapeshellarg экранирует ввод пользователя и заключает его в одинарные кавычки.

Теперь  команда будет достаточно безопасной. Лучше конечно полностью отказаться от запуска серверных команд через PHP.

Так же рекомендуем дополнить проверку по правило «всё запрещено» кроме…

XXE

XXE (внешняя сущность XML) — это атака, которая может привести к атаке LFI или даже к удаленному выполнению кода, когда ваше приложение анализирует XML с плохо настроенным анализатором XML.

Малоизвестная особенность XML позволяет авторам документов включать в свои XML-файлы удаленные и локальные файлы как объекты.

Содержимое / etc / passwd будет выгружено в файл XML.

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

Вывод ошибок возникающих в приложении

Не выводите в продакшен ошибки возникающие в приложении. Это может повлеч к тому что злоумышленник может узнать структуру папок, файлов, таблиц или даже увидеть часть вывода запроса SQL.

Ограничивайте попытки ввода логина

Не позволяйте в вашем приложении повторять попытки «не удачных» попыток ввода логина и пароля, что бы избежать попыток перебора.

Другие очевидные вещи

  1. Всегда обновляйте свой сервер и используемые библиотеки
  2. Подпишитесь на блоги, посвященные безопасности, чтобы быть в курсе лучших практик
  3. Никогда не сохраняйте пароли пользователей в своих логах
  4. Не храните свой код в корне сервера
  5. Относитесь к любому пользовательскому ввода с подозрением
  6. Настройте вашу систему так что бы можно было отделять пользовательские действия от сканеров
  7. Не думайте что сторонний код безопасен
  8. Не тяните код напрямую из GitHub с помощью composer
  9. Установите заголовки для защиты от фреймов, если вы не хотите, чтобы ваш сайт отображался на сторонних доменах.
  10. Если вы работаете с подрядчиками или разработчиками, имеющими небольшой практический опыт, по возможности регулярно проверяйте код.
  11. Если вы не понимаете, как должна работать функция безопасности или почему она используется, спросите кого-нибудь, кто знает. Не игнорируй это
  12. Никогда не пишите свое собственное шифрование если вы не специалист по шифрованию
  13. Отключить списки каталогов для вашего веб-корня
  14. Проверка на стороне клиента не достаточна, проверяйте все данные на стороне сервера
  15. Избегайте десериализации данных от пользователя, это приведет к удаленному выполнению кода.

EN оригинал https://www.raeder.technology/post/intro-to-basic-web-application-security

One Comment

  1. Огромное спасибо автору материала! Много хороших статей у Вас в блоге. Добавила в закладки теперь буду чаще заходить.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *