在典型的网站 nginx 配置(例如博客)中,如何使用 nginxlimit_except
拒绝除典型 http 方法(即GET
和POST
)之外的所有方法?想象一下,它驻留在server
块中,并且块配置为将所有流量重定向到https
和www
。
一个示例如何实现这一点就太好了。
我理解,目前存在争议的做法是:
add_header Allow "GET, POST, HEAD" always;
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
return 405;
}
然而,鉴于if 是邪恶的,探索替代方法是有意义的。
答案1
除了添加文档中已经提到的内容到你的服务器块:
server {
server_name www.example.org;
root /var/www/blog;
...
# add this line (HEAD is implicit - it's a just special case of GET)
limit_except GET POST { deny all; }
...
}
但这样做并不一定是最好的主意:
在选择配置任一方法之前,注意 405 和 403 之间的区别。
- 403 指的是访问客户端没有被授权发出该请求。
- 405 指的是服务器不允许在该 uri 上使用该方法。
两者结合使用是有效的:您可能想告诉用户这里不允许使用 PROPFIND,但是当客户端尝试 PUT 时仍然告诉他虽然这可能是一种可以理解的方法,但特定请求仍然被禁止。
您可以配置的limit_except
只是可能导致 403 的限制子集 - 我看不出limit_except
有比立即使用更清楚的if
方法来触发 405。
下面是一个(未经测试的)示例,它结合了 401、403 和 405 响应,并且应该在典型配置中阐明它们的优先级:
server {
listen 192.0.2.1 ssl http2;
server_name example.org;
ssl_certificate_key /etc/ssl/private/example.org.key;
# nobody shall be able to delete anything on this server
if ($request_method = DELETE)
{
# the concerns about using if are not applicable
# if the block only contains "return" or "rewrite .. last"
return 405;
}
root /var/www/html;
location /.well-known {
alias /var/www/well-known;
}
location / {
# logging in from specific IPs grants acces without HBA login
satisfy any;
allow 203.0.113.0/24;
deny all;
auth_basic_user_file /etc/nginx/users.passwd;
auth_basic "join VPN or hit enter on this prompt:";
limit_except GET {
# block does not inherit the access limitations from above
deny all;
}
location /uploading {
limit_except GET POST {
deny all;
}
proxy_pass http://unix:/run/backend.sock:/upload/;
}
}
}
示例请求:
- DELETE 请求方法会返回 405(符合标准的配置应该添加
Allow
header,这里省略) - 来自 203.0.113.0/24 的 GET 将始终基于 /var/www/html 回复
- 来自 203.0.113.0/24 的 PROPFIND 将返回 403
- 来自其他 IP 的任何请求如果缺少 HBA 标头,将返回 401
- 任何具有 /writable 之外的有效 HBA 的 POST 请求都将返回 403
- 但在 /writable 内部,POST 请求将被代理到后端
- 具有有效 HBA 的 PROPFIND 请求将返回 403
- 除了 DELETE 之外的任何方法都将基于 /var/www/wellknown 回复
答案2
这是 if 不是邪恶的情况。根据有问题发布的链接,在 if 语句中使用 return(并重写 ... last;)是 100% 安全的。