A Nginx module that enables authorizations on sub-requests
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
t * Initial commit. Dec 10, 2011
.gitignore * Initial commit. Dec 10, 2011
CHANGES * Initial commit. Dec 10, 2011
LICENSE * Initial commit. Dec 10, 2011
README.md * Added example about auth_request_set. Feb 17, 2012
README.txt.orig * Initial commit. Dec 10, 2011
config * Initial commit. Dec 10, 2011
ngx_http_auth_request_module.c

README.md

Nginx Auth Request Module

Introduction

The ngx_http_auth_request_module is a module authored by Maxim Dounin, member of the core Nginx team.

Maxim mantains a mercurial repository with the latest version of the code.

The module allows for the insertion of subrequests in the authorization process being handled by Nginx. A more or less obvious application is using this module as a very fast and specific WAF. Meaning a WAF without all the ugliness that something like Apache's mod_security promotes. No bizarre syntax, no reloading of the config. Just add a small script that implements the set of filtering rules that you want to implement. There's no need for any behemoth module that hurts server performance and keep a consultant on a retainer.

Suppose that you want to filter any occurence of the UNION, SELECT and DROP statement in the URI. Suppose that the backoffice of your app is located at /bo. This will do the trick:

location ^~ /bo {
    error_page 401 403 $my_error_page;
    auth_basic 'Classified Access';
    auth_basic_user_file .htpasswd-bo-users;
    auth_request /auth;
    auth_request_set $my_error_page $upstream_http_x_error_page;
}

location /auth {
    if ($request_uri ~* (?:select|union|drop)) {
       return 403;
    }
    return 200;
}

Let's follow the example. There's a request for an URI like this:

/bo/?u=john_doe'; DROP TABLE users--
  1. This request is served by the ^~ /bo location. There the request_auth location redirects to /auth.

  2. Now we're on /auth and we check the if condition regex. We have a match with DROP. Hence we deny authorization by returning a 403 status code, i.e., 403 Access Denied.

  3. If we had requested an acceptable URI then we returned 200 from the /auth location and we proceeded as usual to the following stage.

  4. The $my_error_page variable is set to the value of the X-Error-Page header. This can be used for having specific error pages for each error, for example. This is the error page for 403 and 401 errors.

You might say that this example didn't needed to use auth_request in the first place. Indeed you could have done everything using a simple map directive like this:

map $request_uri $attempt_sql_injection {
    default 0;
    ~*(?:select|union|drop) 1;
}

include it in the http context of your Nginx instance and set:

location ^~ /bo {
    auth_basic 'Classified Access';
    auth_basic_user_file .htpasswd-bo-users;
    
    if ($attempt_sql_injection) {
        return 403;
    }
}

Yes. But this was just an example to give you a hint towards realizing all the potential uses of this handy module.

Here's a quick braindump of potential uses of the auth_request module.

  1. Easily implement two-factor authentication by invoking a script in the /auth location.

  2. Implement Single Sign On systems.

  3. Filter requests and prevent vulnerabilities like SQL injection, XSS, etc.

  4. Complex caching strategies.

  5. Web services implementations.

And much, much more. No limit to your imagination. Dream on.

Module directives

auth_request uri | off

default: off

context: http, server, location

Enables the auth_request module in a given context where the request for authorization will be made to the uri defined.



auth_request_set variable value

default: none

context: http, server, location

Sets the value of the variable to value after the completion of the authorization request.

Caveats

Note that the module discards the request body. Therefore if you're proxying to an upstream you must set proxy_pass_request_body to off and set the Content-Length header to a null string. Here's and example:

location = /auth {
    proxy_pass http://auth_backend;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}

You cannot use proxy_cache/proxy_store or fastcgi_cache/fastcgi_store for requests involving auth_request.

Installation

  1. Grab the source from the mercurial tip or clone this repo:

    git clone git://github.com/perusio/nginx-auth-request-module.git
    
    1. Add the module to the build configuration by adding --add-module=/path/to/ngx_http_auth_request_module.
  2. Build the nginx binary.

  3. Install nginx binary.

  4. Configure contexts where auth_request is enabled.

  5. Done.

Other builds

If you fancy a bleeding edge Nginx package (from the dev releases) for Debian made to measure then you might be interested in my debian Nginx package. Instructions for using the repository and making the package live happily inside a stable distribution installation are provided.

Other Maxim Dounin Nginx modules on Github

  • Nginx Delay: allows for inserting arbitrary delays when serving client requests. Usefull for abuse control and/or poor man's traffic shapping.

Acknowledgments

Thanks to Maxim Dounin for making the module available and being so helpful on the Nginx mailing list answering all kinds of issues and particularly regarding this module.