Назад | Перейти на главную страницу

Nginx не соблюдает необходимость повторной валидации

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

Я использую Amazon s3 в качестве исходного сервера и использую подписанные URL для защиты содержимого. Таким образом, каждый пользователь получает уникальный URL-адрес, срок действия которого истекает через определенное время. Даже несмотря на то, что у каждого пользователя есть уникальный URL, чтобы заставить nginx кэшировать контент независимо, я определил ключ кеша как состоящий только из имени файла запроса (см. Конфигурацию ниже).

Пока это работает очень хорошо. Проблема в том, что если URL-адрес запроса окажется недействительным из-за того, что подпись в строке запроса слишком старая или недействительная, сервер все равно доставит файл. Потому что он кешируется.

Я подтвердил, что первоначальный запрос должен содержать действительную подпись. Если сигнатура в запросе пользователя недействительна, nginx не может получить ее с сервера (конечно).

Теперь я хочу повторный поиск файла при каждом запросе. Этот повторный поиск должен происходить с URL-адресом, указанным пользователем. Если запрос выполнен успешно, кешированный файл должен быть доставлен.

Это именно то поведение, которое должно выполняться с помощью Cache-control: must-revalidate

Итак, я настроил этот заголовок на своем исходном сервере (Amazon s3).

Затем я понял, что nginx не ведет себя соответствующим образом.

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

Вопрос 1: есть ли способ заставить nginx соблюдать обязательную повторную валидацию заголовков в этом контексте?

Вот мой файл конфигурации

proxy_cache_path /home/sbgag/cache keys_zone=MYZONE:10m inactive=365d max_size=10g;
server {
        listen       80;
        server_name test.mydomain.com;
        location / {
                proxy_pass          http://s3-eu-west-1.amazonaws.com;
                proxy_set_header    Host s3-eu-west-1.amazonaws.com;
                proxy_set_header    X-Real-IP $remote_addr;
                proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_cache_key         "$request_filename";
                more_set_headers "X-My-Proxy-Cache-Key $request_filename";
                more_set_headers "X-My-Proxy-Cache-realpath_root $realpath_root";
                more_set_headers "X-My-Proxy-Cache-uri $uri";
                proxy_cache            MYZONE;
                proxy_cache_valid      200  365d;
                proxy_cache_use_stale  error timeout invalid_header updating http_500 http_502 http_503 http_504;
                more_set_headers "X-AppServer $upstream_addr";           # Backend Server / Port
                more_set_headers "X-AppServer-Status $upstream_status";  # Backend HTTP Status
                more_set_headers "X-Cache $upstream_cache_status";       # HIT / MISS / BYPASS / EXPIRED
        }
}

Также я нашел это журнал изменений

*) Feature: the "proxy_cache_revalidate", "fastcgi_cache_revalidate",
   "scgi_cache_revalidate", and "uwsgi_cache_revalidate" directives.

Так что я подумал, что поиграю с этим. После доведения моего nginx до новейшей версии я установил время кеширования на 0 с. С 0s файл никогда не кешируется, поэтому я установил его на 1s.

Это производит почти поведение, которое я хочу. Это вызывает повторную проверку файла на сервере через 1 секунду. Затем он повторно подтверждается подписанным URL-адресом, предоставленным пользователем. Если он неверен, значит, он не работает. Кроме того, файл не удаляется, поскольку кажется, что nginx удаляет файлы не сразу, а только при заполнении места. Таким образом, даже если истекло время ожидания файла и даже если другой клиент предоставил недопустимый URL-адрес, следующий клиент с действительным URL-адресом может загрузить из кеша.

Однако в 1-секундном таймфрайме каждый может скачать, но это меня не беспокоит.

Хорошо, это почти то, что я хочу, но что мне не нравится, так это то, что это уродливая работа, основанная на поведении, которое более случайное, чем функциональное.

Вопрос 2: Нет лучшего способа?

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

Маби, подойдет даже правило перезаписи. Перезапись в сценарий с картой перезаписи и вывод URL-адреса только в том случае, если проверка прошла успешно.

Любой вклад приветствуется!

Я думаю, что то, что вы ищете, на самом деле добавляет это:

proxy_cache_bypass $ http_cache_control;

Таким образом, отправка запроса с установленным заголовком Cache-Control: must-revalidate будет обходить кеш.