Limit http request methods in Nginx (authentication except for GET)

Written by - 0 comments

Published on May 31st 2016 - Listed in Nginx Linux


Was looking for a way to tell Nginx to let all GET requests through but all other requests (e.g. POST, PUT, etc) should be authenticated.

On my research I found a lot of examples using "if", like this one (found on https://www.acunetix.com/blog/articles/nginx-server-security-hardening-configuration-1/):

if ($request_method !~ ^(GET|HEAD|POST)$ )
{
    return 444;
}

However there are two problems.

1) if is evil: https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/ 

2) basic auth does not work within an if clause in Nginx. So the following snippet doesn't work:

if ($request_method !~ ^GET$ )
{
  auth_basic "Login required";
  auth_basic_user_file /etc/nginx/auth/.htpasswd;
}

Belive me, I tried it and fell on my nose... On my research WHY it fails, I came across this page: https://t37.net/the-good-the-bad-and-the-ugly-of-virtual-hosting-with-nginx.html, which explains it nicely:

The reason why it fails is because if is not part of the general configuration module as one should believe. if is part of the rewrite module and auth_basic is another module. That’s one of the reason why the Nginx community thinks if is evil.

Eventually I came across the limit_except method, which is part of the Nginx core module. By using this method, one can define special limits for http request methods. The documentation (http://nginx.org/en/docs/http/ngx_http_core_module.html#limit_except) describes the method in a bizarre way though:

Limits allowed HTTP methods inside a location. The method parameter can be one of the following: GET, HEAD, POST, PUT, DELETE, MKCOL, COPY, MOVE, OPTIONS, PROPFIND, PROPPATCH, LOCK, UNLOCK, or PATCH. Allowing the GET method makes the HEAD method also allowed. Access to other methods can be limited using the ngx_http_access_module and ngx_http_auth_basic_module modules directives

What I mean with bizarre: It's not clear whether the limitation is now for the mentioned request methods or for the unlisted request methods. But a configuration change quickly showed me that it works the following way:

  location /api/ {

    # Only allow GET, all other methods require basic auth
    limit_except GET {
      auth_basic           "Login required";
      auth_basic_user_file /etc/nginx/auth/.htpasswd;
    }

    include /etc/nginx/proxy.conf;
    proxy_pass       http://127.0.0.1:8080;
  }

The comment I added just above limit_except explains it: Set a limit for all http request methods (load the auth_basic stuff) EXCEPT the request method is GET.

Works nicely and I didn't have to use "if" either.


Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.