web-dev-qa-db-ja.com

Nginxは再検証する必要があります

Nginxをキャッシングリバースプロキシとして使用したい。また、nginxで達成できると思った特別な要件もあります。

OriginサーバーとしてAmazons3を使用しており、コンテンツを保護するために signed urls を使用しています。したがって、すべてのユーザーは、特定の時間が経過すると期限切れになる一意のURLを取得します。すべてのユーザーが一意のURLを持っている場合でも、nginxがコンテンツをキャッシュするようにするために、キャッシュキーをリクエストファイル名のみで構成されるものとして定義しました(以下の構成を参照)。

これまでのところ、これは非常にうまく機能します。問題は、クエリ文字列の署名が古すぎるか無効であるためにリクエストURLが無効になる場合、サーバーはとにかくファイルを配信することです。キャッシュされているからです。

最初のリクエストには有効な署名が含まれている必要があることを確認しました。ユーザーリクエストの署名が無効な場合、nginxはサーバーから署名を取得できません(もちろん)。

今私が欲しいのは、リクエストごとにファイルを再検索することです。この再検索は、ユーザーが指定したURLで実行する必要があります。リクエストが成功した場合、キャッシュされたファイルが配信されます。

これはまさにCache-control: must-revalidateを使用して実行する必要のある動作です。

そこで、Originサーバー(Amazon s3)でこのヘッダーを構成しました。

その後、nginxがそれに応じて動作しないことに気付きました。

そのため、ファイルはOriginサーバーで検証せずにキャッシュから直接配信されます。したがって、不正な署名は認識されず、ユーザーはダウンロードできます。

質問1:このコンテキストでnginxがmust-revalidationヘッダーを尊重するようにする方法はありますか?

これが私の設定ファイルです

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
        }
}

また、私はこれを見つけました changelog

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

だから遊んでみようと思いました。 nginxを最新バージョンにした後、キャッシュ時間を0に設定しました。 0の場合、ファイルはキャッシュされないため、1に設定します。

これにより、ほぼ必要な動作が生成されます。これにより、ファイルは1秒後にサーバー上で再検証されます。次に、ユーザーが指定した署名付きURLを使用して再検証されます。正しくない場合は失敗します。また、nginxはファイルをすぐに削除するのではなく、スペースがいっぱいになったときにのみ削除するように見えるため、ファイルは削除されません。そのため、ファイルがタイムアウトした場合や、別のクライアントが無効なURLを提供した場合でも、有効なURLを持つ次のクライアントはキャッシュからダウンロードできます。

1秒のタイムフライムでは、誰でもダウンロードできますが、私にとってはそれほど心配する必要はありません。

さて、これはほとんど私が望んでいることですが、私が好きではないのは、機能的というよりも偶発的な行動に基づく醜い回避策であるということです。

質問2:もっと良い方法はありませんか?

私が最も望んでいるのは、バックグラウンドで自分のスクリプトを使用してリクエストを検証できる検証スクリプトにリクエストを渡すことです。そして、そのスクリプトが成功を返した場合にのみ、ダウンロードが許可されます。そして、既存の実績のあるnginxキャッシングアルゴリズムを利用します。

Mabyは書き換えルールでもかまいません。リライトマップを使用してスクリプトにリライトし、検証が成功した場合にのみURLを出力します。

すべての入力が適用されます!

3
The Shurrican

私はあなたが探しているのは実際にこれを追加していると思います:

proxy_cache_bypass $ http_cache_control;

このように、設定されたCache-Control:must-revalidateヘッダーを使用してリクエストを送信すると、キャッシュがバイパスされます。

1
marcinkuzminski