Как использовать timestamp для защиты от replay-атак

Как защититься от replay-атак с помощью простой настройки на бэкенде.

Суть кратко

DFP передаёт в расшифрованном payload поле timestamp — время, когда был сформирован результат.

Проверяйте timestamp на своём бэкенде. Если ответ старше несколько секунд относительно текущего времени UTC, не используйте его. Так вы защититесь от replay-атаки (атаки повторного воспроизведения): ситуации, когда старый ответ DFP пытаются отправить повторно как свежий, чтобы эксплуатировать ваш сервис.

Как может произойти replay-атака

Все ответы DFP проходят через браузер пользователя: сначала DFP возвращает ответ браузеру, а потом скрипт в браузере отправляет этот ответ на ваш бэкенд. Именно браузер здесь слабое место: в нём можно попытаться подменить свежий ответ DFP на старый.

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

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

Злоумышленник делает так:

  1. Открывает сайт в обычном браузере с нормального IP-адреса.

  2. Получает настоящий ответ DFP для чистого окружения: обычный браузер, не датацентр, не автоматизация, низкий bot_score.

  3. Сохраняет полный ответ DFP.

  4. Запускает автоматизацию: скрипт, который отправляет большое количество запросов.

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

  6. Если бэкенд не проверяет timestamp, он может принять старый ответ как результат текущей проверки и решить, что запрос пришёл от обычного пользователя.

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

DFP передаёт в payload поле timestamp, поэтому вы можете проверить свежесть ответа и не принимать один и тот же результат повторно.

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

Проверяйте timestamp после расшифровки payload.

Проверку должен выполнять ваш бэкенд. Не используйте время из браузера: его можно подменить. Опирайтесь только на timestamp.

Ваш бэкенд:

  1. Получает ответ DFP от браузера.

  2. Расшифровывает payload.

  3. Читает timestamp.

  4. Сравнивает timestamp с текущим временем UTC.

  5. Если ответ свежий — продолжает обработку. Если слишком старый — отклоняет его.

Пример политики:

const MAX_DFP_RESPONSE_AGE_MS = 5_000;

const responseTimestamp = Date.parse(payload.timestamp);
const responseAge = Date.now() - responseTimestamp;

if (
  !Number.isFinite(responseTimestamp) ||
  responseAge < 0 ||
  responseAge > MAX_DFP_RESPONSE_AGE_MS
) {
  throw new Error('DFP response is expired');
}

acceptDfpResult(payload);

Допустимое окно «свежести» timestamp определяете вы в соответствии со своим бизнес-сценарием.