使用 limit_except 拒绝除 GET、HEAD 和 POST 之外的所有内容

使用 limit_except 拒绝除 GET、HEAD 和 POST 之外的所有内容

在典型的网站 nginx 配置(例如博客)中,如何使用 nginxlimit_except拒绝除典型 http 方法(即GETPOST)之外的所有方法?想象一下,它驻留在server块中,并且块配置为将所有流量重定向到httpswww

一个示例如何实现这一点就太好了。

我理解,目前存在争议的做法是:

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

示例请求:

  1. DELETE 请求方法会返回 405(符合标准的配置应该添加Allowheader,这里省略)
  2. 来自 203.0.113.0/24 的 GET 将始终基于 /var/www/html 回复
  3. 来自 203.0.113.0/24 的 PROPFIND 将返回 403
  4. 来自其他 IP 的任何请求如果缺少 HBA 标头,将返回 401
  5. 任何具有 /writable 之外的有效 HBA 的 POST 请求都将返回 403
  6. 但在 /writable 内部,POST 请求将被代理到后端
  7. 具有有效 HBA 的 PROPFIND 请求将返回 403
  8. 除了 DELETE 之外的任何方法都将基于 /var/www/wellknown 回复

答案2

这是 if 不是邪恶的情况。根据有问题发布的链接,在 if 语句中使用 return(并重写 ... last;)是 100% 安全的。

相关内容