Серверные уязвимости
Ошибки обработки запросов на сервере — SSRF и DNS rebinding, небезопасная десериализация, HTTP request smuggling, небезопасная загрузка файлов, атаки через Host, отравление кэша и file inclusion.
14 вопросов
JuniorТеорияОчень частоЧто такое Server-Side Request Forgery (SSRF) и почему allowlist адресов назначения лучше denylist внутренних адресов?
Что такое Server-Side Request Forgery (SSRF) и почему allowlist адресов назначения лучше denylist внутренних адресов?
SSRF — это когда сервер сам запрашивает URL, которым управляет клиент: запрос уходит изнутри сети и достаёт до внутренних сервисов. Denylist внутренних адресов не бывает полным, а allowlist хостов и портов запрещает остальное.
Типичные ошибки
- ✗Считать SSRF браузерной проблемой, которую решает CORS
- ✗Верить, что denylist приватных диапазонов — полный фильтр
- ✗Считать, что без возврата ответа импакта нет
Уточняющие вопросы
- →Почему редирект от разрешённого хоста требует повторной проверки?
- →Какие схемы и порты должен пропускать allowlist исходящих запросов?
JuniorТеорияОчень частоПочему сервер не должен доверять заголовку Content-Type и расширению имени загруженного файла?
Почему сервер не должен доверять заголовку Content-Type и расширению имени загруженного файла?
Оба значения приходят в запросе, клиент задаёт их сам, и любое содержимое можно объявить картинкой. Сервер определяет тип по байтам, хранит файл вне web-root под сгенерированным именем и отдаёт его без исполнения.
Типичные ошибки
- ✗Доверять заявленному Content-Type как измеренному сервером
- ✗Проверять расширение вместо реальных байтов файла
- ✗Класть загрузки в web-root под клиентским именем
Уточняющие вопросы
- →Почему хранение вне web-root важнее любой проверки имени?
- →Что даёт перекодирование принятой картинки сверх определения типа?
SeniorТеорияОчень частоЧто такое обработка внешних сущностей XML (XXE) и каково правильное исправление на уровне парсера?
Что такое обработка внешних сущностей XML (XXE) и каково правильное исправление на уровне парсера?
Документ может объявить сущность со значением-URI, и парсер с включённым разрешением внешних сущностей загрузит её, поэтому разбор читает файлы или шлёт запросы от имени сервера. Лечится в настройке парсера.
Типичные ошибки
- ✗Верить, что документ не может объявить свои сущности
- ✗Пытаться фильтровать ввод вместо настройки парсера
- ✗Считать, что разбор не может отправлять исходящие запросы
Уточняющие вопросы
- →Почему отключение определений типа документа лучше denylist сущностей?
- →Какие ещё форматы документов попадают к парсеру с той же настройкой?
JuniorТеорияЧастоЧем опасна десериализация недоверенных данных и какой безопасный вариант по умолчанию для внешнего ввода?
Чем опасна десериализация недоверенных данных и какой безопасный вариант по умолчанию для внешнего ввода?
Нативный десериализатор создаёт любые названные в байтах типы, поэтому ввод решает, какие классы появятся и какие обработчики вызовутся: это исполнение, а не разбор. Безопасен формат только с данными в объявленные типы.
Типичные ошибки
- ✗Считать риском лишь слишком большие или битые данные
- ✗Проверять данные, когда объекты уже созданы
- ✗Верить, что подпись делает безопасным любой формат
Уточняющие вопросы
- →Почему проверка после создания объектов уже опоздала?
- →Что даёт явный allowlist типов, если формат содержит только данные?
MiddleТеорияЧастоПочему эндпоинты метаданных облачных инстансов сделали класс атак SSRF критичным и что меняет IMDSv2?
Почему эндпоинты метаданных облачных инстансов сделали класс атак SSRF критичным и что меняет IMDSv2?
Сервис метаданных отвечает на неаутентифицированные запросы с инстанса и может выдать учётные данные роли, поэтому один серверный запрос превращается в доступ к облаку. IMDSv2 требует токен через PUT и низкий hop limit.
Типичные ошибки
- ✗Оценивать доступ к метаданным как раскрытие информации, а не кражу учётных данных
- ✗Полагаться на запись адреса метаданных в denylist исходящих
- ✗Считать, что короткий срок жизни учётных данных снимает импакт
Уточняющие вопросы
- →Почему hop limit важен не меньше сессионного токена?
- →Какое ограничение прав уменьшит ущерб, если метаданные всё же достигнуты?
MiddleТеорияЧастоЧто такое mass assignment и почему привязка тела запроса прямо к доменному объекту его вызывает?
Что такое mass assignment и почему привязка тела запроса прямо к доменному объекту его вызывает?
Биндер пишет в тип каждое найденное в теле поле, поэтому атрибуты вроде роли, владельца и баланса проставляются, стоит их упомянуть. Привязка идёт во входную модель только с редактируемыми полями.
Типичные ошибки
- ✗Путать это с массовыми обновлениями в базе данных
- ✗Считать, что биндер заполняет только документированные поля
- ✗Прятать поля из ответов вместо ограничения привязки
Уточняющие вопросы
- →Почему allowlist привязываемых полей надёжнее denylist защищённых?
- →Как задавать поля владения, если они не приходят из запроса?
MiddleТеорияЧастоКак клиентское имя файла позволяет записать его вне каталога загрузок и чем это предотвращается?
Как клиентское имя файла позволяет записать его вне каталога загрузок и чем это предотвращается?
Склейка полученного имени с путём хранения позволяет выйти из каталога, и файл ложится туда, куда указывает имя. Лечится генерацией имени на сервере либо отказом для итогового пути вне базового каталога.
Типичные ошибки
- ✗Считать, что фреймворк уже нормализовал полученное имя
- ✗Фильтровать подозрительные символы вместо разбора итогового пути
- ✗Верить, что обход каталога в имени даёт только чтение
Уточняющие вопросы
- →Почему сгенерированное имя надёжнее очистки полученного?
- →Что проверяют после разбора пути и относительно какой базы?
MiddleТеорияИногдаКак DNS rebinding обходит схему проверки URL перед запросом и что закрывает этот разрыв?
Как DNS rebinding обходит схему проверки URL перед запросом и что закрывает этот разрыв?
Проверка резолвит имя и одобряет адрес, а запрос резолвит заново и получает другой — разрыв между проверкой и использованием. Закрывается так: один резолв, проверка этого адреса и соединение именно с ним.
Типичные ошибки
- ✗Проверять строку имени хоста вместо адреса, к которому реально идёт соединение
- ✗Считать, что один результат резолва действителен весь запрос
- ✗Считать rebinding проблемой только браузера
Уточняющие вопросы
- →Почему редирект нужно проверять по тем же правилам адресов?
- →Где исходящий прокси упрощает применение фиксации адреса?
SeniorТеорияИногдаСерверный запрос ничего не возвращает вызывающему — как обнаружить его в своей телеметрии и ограничить?
Серверный запрос ничего не возвращает вызывающему — как обнаружить его в своей телеметрии и ограничить?
В ответе не видно ничего, поэтому смотрят, что порождает сервер: логи резолвера, записи исходящих соединений и логи прокси покажут ненужные адреса. Ограничивает исходящий прокси с allowlist и без переходов по редиректам.
Типичные ошибки
- ✗Считать отсутствие ответа доказательством отсутствия импакта
- ✗Искать признаки только в логах входящих запросов
- ✗Разрешать переход по редиректам после проверки
Уточняющие вопросы
- →Чем полезны логи запросов к резолверу, если соединение не удалось?
- →Что помимо имени хоста входит в allowlist исходящего прокси?
SeniorТеорияИногдаЧто такое отравление веб-кэша через неключевой ввод и как защитить общий кэш?
Что такое отравление веб-кэша через неключевой ввод и как защитить общий кэш?
Ввод, который меняет ответ, но не входит в ключ кэша, позволяет одним запросом сохранить запись для всех последующих клиентов. Ключ и влияющие данные согласуют: заголовок либо в ключе, либо срезан на границе.
Типичные ошибки
- ✗Считать, что в общий кэш попадает только статика
- ✗Считать это укреплением узла, а не проблемой состава ключа
- ✗Думать, что кодирование отражённого заголовка снимает эффект кэша
Уточняющие вопросы
- →Почему совпадение ключа и влияющих данных работает в обе стороны?
- →Чем cache deception отличается от отравления по тому, что сохраняется?
SeniorТеорияИногдаПочему заголовок Host — недоверенный ввод и что ломается, когда приложение строит из него URL?
Почему заголовок Host — недоверенный ввод и что ломается, когда приложение строит из него URL?
Host приходит в запросе, то есть его выбирает клиент. Приложение, собирающее из него абсолютные ссылки, может отправить ссылку сброса пароля на чужой адрес, а кэш сохранит такой ответ. Origin берут из конфигурации.
Типичные ошибки
- ✗Считать, что веб-сервер нормализует Host до приложения
- ✗Строить абсолютные ссылки из заголовков запроса, а не из конфигурации
- ✗Забывать, что кэш может сохранить испорченный ответ
Уточняющие вопросы
- →Какие ещё заголовки пересылки требуют того же отношения, что и Host?
- →Почему ссылка сброса пароля — классическое место проявления?
SeniorТеорияИногдаЧем вызвана атака HTTP request smuggling и почему это расхождение парсинга фронтенда и бэкенда?
Чем вызвана атака HTTP request smuggling и почему это расхождение парсинга фронтенда и бэкенда?
Два сервера на одном соединении расходятся, где кончается запрос: один доверяет Content-Length, другой Transfer-Encoding, и остаток байтов начинает следующий. Лечение — единая трактовка границ и отказ неоднозначным заголовкам.
Типичные ошибки
- ✗Объяснять это переупорядочиванием пакетов, а не трактовкой заголовков
- ✗Путать сам рассинхрон с последствиями в кэше
- ✗Считать, что понижение с HTTP/2 уменьшает неоднозначность границ
Уточняющие вопросы
- →Почему переиспользование соединения делает рассинхрон устойчивым?
- →Что прокси должен делать с запросом, несущим оба заголовка границ?
SeniorДебаггингИногдаЭтот обработчик загрузки аватарки доверяет запросу и тип файла, и путь сохранения — найдите и исправьте дефекты.
Этот обработчик загрузки аватарки доверяет запросу и тип файла, и путь сохранения — найдите и исправьте дефекты.
Три дефекта доверия. Заявленный тип задаёт клиент — определяем тип по байтам. Полученное имя склеивается с путём хранения — имя генерирует сервер. Каталог лежит в web-root — выносим наружу и отдаём без исполнения.
Открыть задачу →Типичные ошибки
- ✗Починить проверку типа, оставив клиентское имя файла
- ✗Оставить каталог хранения внутри web-root
- ✗Сначала записать файл, а проверять его потом
Уточняющие вопросы
- →Почему сгенерированное имя полностью снимает вопрос обхода каталога?
- →Что должен выставлять отдающий обработчик, чтобы браузер не трактовал файл?
SeniorДизайнРедкоПлатёжный сервис читает конверты заданий из очереди, куда пишет любой партнёр, и сегодня восстанавливает каждый конверт нативным десериализатором платформы прямо в доменные объекты; у консьюмеров есть доступ к базе. Ограничения: стороннего producer нельзя перевести на новую клиентскую библиотеку в этом квартале, конверт должен остаться совместимым с уже летящими заданиями, обработку нельзя останавливать на время миграции, и нельзя вводить библиотеку, которая берёт типы из полезной нагрузки. Спроектируйте защиту десериализации — целевой формат конверта, как ограничивается множество создаваемых типов, где относительно разбора проверяются целостность и полномочия и какой сигнал докажет, что старый путь больше не используется.
Платёжный сервис читает конверты заданий из очереди, куда пишет любой партнёр, и сегодня восстанавливает каждый конверт нативным десериализатором платформы прямо в доменные объекты; у консьюмеров есть доступ к базе. Ограничения: стороннего producer нельзя перевести на новую клиентскую библиотеку в этом квартале, конверт должен остаться совместимым с уже летящими заданиями, обработку нельзя останавливать на время миграции, и нельзя вводить библиотеку, которая берёт типы из полезной нагрузки. Спроектируйте защиту десериализации — целевой формат конверта, как ограничивается множество создаваемых типов, где относительно разбора проверяются целостность и полномочия и какой сигнал докажет, что старый путь больше не используется.
Переводим конверт на формат только с данными, разбираемый во входную модель с фиксированным набором полей, неизвестные типы отклоняем. Подпись проверяем до разбора, полномочия — после. Переключаемся, когда у нативного читателя ноль вызовов.
Типичные ошибки
- ✗Оставлять нативный десериализатор за denylist имён классов
- ✗Проверять подпись уже после разбора полезной нагрузки
- ✗Считать закрытую очередь доказательством доверенности данных
Уточняющие вопросы
- →Почему проверка целостности идёт до разбора, а не после?
- →Как входная модель сохраняет совместимость конверта?