Nginx 不遵守必须重新验证的规定

Nginx 不遵守必须重新验证的规定

我想使用 nginx 作为缓存反向代理。我还有一个特殊要求,我认为可以用 nginx 来实现。

我使用 Amazon s3 作为原始服务器,并使用签名网址以保护内容。因此,每个用户都会获得一个在一定时间后过期的唯一 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 升级到最新版本后,我将缓存时间设置为 0s。如果设置为 0s,则文件永远不会被缓存,因此我将其设置为 1s。

这产生了几乎我想要的行为。它会导致文件在 1 秒后在服务器上重新验证。然后使用用户提供的签名 URL 重新验证。如果不正确,则失败。此外,文件不会被删除,因为 nginx 似乎不会立即删除文件,而只会在空间已满时删除。因此,即使文件超时,即使另一个客户端提供了无效的 URL,下一个具有有效 URL 的客户端也可以从缓存中下载。

然而,在 1 秒的时间范围内,每个人都可以下载,但这对我来说并不是什么问题。

好的,这几乎就是我想要的,我不喜欢的是,它是一种丑陋的工作,它基于偶然而非功能性的行为。

问题2:没有更好的办法吗?

我最希望的是将请求传递给验证脚本,这样我就可以在后台使用我自己的脚本来验证请求。只有当该脚本返回成功时,才允许下载。然后利用现有的、经过验证的 nginx 缓存算法。

也许重写规则也可以。使用重写映射重写脚本,并且仅在验证成功时输出 URL。

欢迎任何意见!

答案1

我认为您正在寻找的实际上是添加这个:

代理缓存绕过$http_cache_control;

这样,发送设置了 Cache-Control:must-revalidate 标头的请求将绕过缓存。

相关内容