Запросы и ответы HTTP — Примеры
Пример 1 — Повтор, создающий второй заказ
Клиент сообщает, что создание иногда приходит дважды. Обмен ниже — тот, что предшествовал этому. Скажите, какая инструкция опасна, почему метод сделал этот повтор небезопасным и что изменить.
запрос
POST /orders
Host: адрес магазина
Content-Type: application/json
Content-Length: 84
ответ
301
Location: тот же узел и путь, защищённая схема
Cache-Control: max-age=31536000
Решение
причина: 301 кэшируется и запоминается, поэтому каждый следующий запрос
повторяется против защищённой схемы; POST не безопасно повторять,
и повтор может создать дубликат
изменить: используйте 302 для условия, которое может измениться; оставляйте 301
только для постоянного переноса
помечайте ответы создающего эндпоинта как некэшируемые
сохранить: GET по-прежнему повторяется свободно; PUT /orders/42 безопасно повторять
Постоянное перенаправление помнится долго после того, как условие, которое его оправдало, исчезло, и в паре с методом, не безопасным для повтора, оно превращает каждую повторную попытку в возможный дубликат. Временное перенаправление плюс указания по кэшированию, отвечающие смыслу эндпоинта, оставляют решение клиенту. Обычная ошибка — считать перенаправление безобидной сантехникой: это постоянная инструкция клиенту на все будущие запросы.
Пример 2 — Заголовок пересылки, который выбрал вызывающий
Запрос доходит до приложения с заголовком происхождения, который написал вызывающий. Теперь приложение ему доверяет. Перепишите обработку так, чтобы ближайший компонент задавал заголовок, а недоверенный ввод не мог.
как видит приложение
GET /profile
Host: внутреннее имя приложения
X-Forwarded-For: 198.51.100.7, 10.0.0.5
Решение
на прокси: перезаписывайте X-Forwarded-For адресом, который он наблюдал, никогда
не дописывайте недоверенный ввод и отбрасывайте заголовок у запросов
извне
в приложении: читайте значение только из доверенного прокси, иначе используйте
адрес узла самого соединения
также: аутентифицированный ответ профиля помечен Cache-Control: private
Заголовки несут контекст, которого не может дать тело, но задавать их должен компонент, ближайший к клиенту, а приложение обязано брать их только от этого компонента, иначе любой вызывающий может заявить любое происхождение. Тот же обзор относится и к кэшированию, где аутентифицированный ответ, помеченный приватным, не сохраняется общим кэшем. Обычная ошибка — доверять заголовку потому, что он присутствует, а значение выглядит правдоподобно.