Десять основных проблем аудита безопасности Laravel

Источник: «Top 10 Laravel Audit Security Issues»
Давайте углубимся и рассмотрим десять наиболее распространённых проблем безопасности, которые я обнаружил во время своих аудитов безопасности Laravel приложений.

С начала 2022 года я проводил аудиты безопасности и тесты на проникновение для Laravel приложений. Я проверял приложения всех размеров, от крошечных приложений с несколькими контроллерами до огромных приложений с множеством модулей и множеством различных стилей кодирования и структур приложений.

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

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

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

10 → Недостаточная валидация ввода

Обычно недостаточная валидация ввода разбросана по контроллерам. Часто это валидатор, проверяющий ожидаемые входящие ключи (хотя иногда и этого нет), а затем сразу после этого будет использоваться request()->all(), отправляя данные в модели, события и т.д. Без надлежащей проверки легко внедрить вредоносные значения, чтобы вызвать ошибки, инъекции и многое другое.

Например, обычной защитой от массового назначения считается $fillable в модели, но если $fillable включает флаг admin для администратора портала, то любой может создать нового пользователя-администратора со страницы регистрации… (и да, это реальный пример)

9 → Отсутствие целостности подресурса

SRI добавляет уровень защиты от скомпрометированных сторонних скриптов, влияющих на ваш сайт, и, на мой взгляд, серьёзно недооценивается. Риск заключается в том, что сторонние сценарии и стили могут быть изменены для включения вредоносного кода, такого как Megacart, кейлоггеры, криптомайнеры и т.д. Если на вашем сайте есть скомпрометированный скрипт, ваши пользователи подвергаются риску, даже если ваше приложение не было скомпрометировано.

SRI работает определяя хэш целостности для каждого тэга <script> и <style> загружаемый сторонним ресурсом, который браузер проверяет перед загрузкой ресурса. Если хэш не совпадает, ресурс блокируется.

Большинство сайтов, которые я проверял, не загружали ресурсы от третьих лиц и, следовательно, в любом случае не нуждались в SRI, иначе я бы ожидал, что он будет намного выше в списке!

8 → Недостаточное ограничение скорости

Ограничение скорости (в данном случае имеется ввиду временная задержка между подключениями, например, попытка логина для одного IP/username — раз в 5 секунд) необходимо для ограничения атак ботов и предотвращения злоупотреблений, тем не менее часто можно найти конечные точки, на которых отсутствует ограничение скорости. Это особенно важно, когда речь заходит о таких маршрутах, как аутентификация, или о запросах конфиденциальной информации, например о существовании учётных записей пользователей. Например, я обнаружил, что в маршруте основанном на SMS MFA отсутствует ограничение скорости, а срок действия 6-значного кода истекает через 5 минут. Это было тривиально за брутфорсить валидный код и войти.

Тем не менее ограничение скорости может быть сложной задачей — вы основываете его на IP, или имени пользователя, или на том и другом? Или что-то другое? Это зависит от маршрута, но иметь что-то определённо лучше, чем ничего. Так что не упускайте из виду!

7 → Межсайтовые скрипты (XSS)

Одна из самых неожиданных записей в Топ-10, но, вероятно, она намного ниже, чем вы ожидали! XSS обычно появлялся на одном маршруте, через один ввод из-за чего-то вроде Markdown (не безопасный по умолчанию) или ограниченного форматирования, которое пострадало от тонкого обхода экранирования.

Лучшая стратегия — обратить внимание на эти надоедливые неэкранированные blade-тэги ({!! … !!}) и необработанные HTML директивы, такие как v-html, и убедиться, что всё правильно экранировано, что функции безопасности Markdown включены, а предоставленный пользователем HTML очищается. Я рекомендую избегать этих тегов, насколько это возможно, чтобы любое использование действительно выделялось и могло быть легко идентифицировано и рассмотрено.

6 → Устаревшие и уязвимые зависимости

Ещё одна неудивительная запись… Когда вы в последний раз запускали composer update или npm update?

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

Я рекомендую обновлять всё еженедельно или ежемесячно и использовать такие инструменты, как composer audit --locked и npm audit в вашей системе сборки, чтобы блокировать развёртывание при обнаружении уязвимостей. Я также предлагаю свести ваши зависимости к минимуму, и всё, что можно легко заменить простым middleware или обёрткой, должно быть таковым.

5 → Небезопасное использование функций

Я сбился со счёта, сколько раз видел, как md5(time())md5(microtime())!) использовались с тех пор, как я начал работать с PHP, вероятно, я даже использовал их когда-то! И, к сожалению, эта тенденция сохраняется и по сей день. Хуже того, это часто используется для генерации случайных токенов или уникальных имён файлов. За исключением того, что это не случайно и не уникально. Это невероятно легко угадать и использовать брутфорс, и атаки коллизий также могут быть весьма тривиальными.

Бьюсь об заклад, если вы прямо сейчас войдёте в свою кодовую базу и поищите md5(, вы обнаружите, что он где-то небезопасно используется...

Это касается не только md5(time()), но и других функций, таких как rand() и array_rand(), которые не являются криптографически безопасными, и им не следует доверять во всём, что требует безопасности.

Всегда используйте правильные безопасные генераторы случайных чисел, random_int() и Str::random() для безопасного генерирования значений.

4 → Отсутствующие заголовки безопасности

Теперь мы переходим к дополнительным уровням защиты, которые не совсем понятны. Веб-браузеры включают в себя множество действительно потрясающих функций безопасности, вам нужно просто включить их на своём сайте с помощью заголовка ответов. Хотя их отсутствие напрямую не открывает ваш сайт для взлома, они помогают предотвратить такие вещи, как кликджекинг, утечку информации о реферере, XSS и другие атаки путём внедрения, атаки с понижением HTTPS и т.д. Включения многих из этих заголовков безопасности тривиально, но большинство сайтов не включает даже самые простые…

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

3 → Отсутствует Политика Безопасности Контента (CSP)

Политики безопасности контента (CSP) настолько важны, что я выделил им отдельное место в Топ-10. CSP — это вторичная линия защиты от XSS и кликджекинга, и они дают представление о том, какие скрипты, стили, шрифты, формы, фреймы и т.д. работают в вашем приложении. CSP сообщает браузеру, какие ресурсы разрешено использовать на сайте, и он будет блокировать и/или сообщать о любых нарушениях политики, предотвращая атаки XSS и обеспечивая вам видимость того, что происходит на вашем сайте.

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

Я опубликовал своё CSP middleware как простой способ начать работу с CSP: GitHub Gist

2 → Отсутствует авторизация

Это включает в себя множество вещей, связанных с авторизацией (и в некотором роде аутентификацией). Я видел: небезопасные прямые ссылки на объекты (IDOR), отсутствие signed, auth и policy middleware, забытые вызовы authorize(), веб-хуки без валидации и т.д. В конечном счёте, код на самом деле не проверял, разрешено ли запрашивающей стороне делать то, что она хотела.

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

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

1 → Доступные ключи API и пароли

Сколько раз говорить? Не коммитьте секреты в Git!

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

Подумайте куда идёт ваш код... Он есть на всех машинах разработчиков, используется совместно с подрядчиками, на GitHub, Bitbucket, GitLab и т.д., в сторонних сервисах и инструментах сборки. Он разбросан по разным местам. В то время как ваши ключи API разблокируют биллинг, хранилище файлов, личную информацию, резервные копии, инфраструктуру и т.д. Так много конфиденциальной информации и доступа, и если она попадёт в чужие руки, ваша репутация исчезнет.

Я понимаю, что есть руководства, которые рекомендуют коммитить эти вещи, так что я понимаю, почему это происходит. Но это то, над чем нам как сообществу нужно упорно работать, чтобы остановить это.

Если вы случайно закоммитите учётные данные, убедитесь, что отозвали их в источнике. Это помешает кому-либо использовать их, если они их найдут. Я также предлагаю использовать такие инструменты как Gitleaks и TruffleHog для поиска секретов в ваших кодовых базах.

Бонус → Отсутствие файла security.txt!

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

security.txt — это текстовый файл, размещённый в /.well-known/security.txt, в котором указаны ваши контакты данные на случай, если кто-то обнаружит проблему безопасности на вашем сайте. Это позволяет специалистам по безопасности очень легко связаться с вами, сокращая время и усилия, необходимые для сообщения о проблемах, чтобы вы могли быстрее их исправить.

Сгенерируйте его на https://securitytxt.org

Итог

Это мой Топ-10! Были ли сюрпризы? Вещи, которые нужно проверить в собственных приложениях? Может быть, вы были с чем-то не согласны? Присоединитесь к обсуждению в Twitter, Fediverse, или Substack Notes.

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

Дополнительные материалы

Предыдущая Статья

Новое в Symfony 6.3 — Компонент AssetMapper

Следующая Статья

CGI, FastCGI, php-fpm, nginx и Laravel