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