ngx_xss: Native support for cross-site scripting in an nginx

agentzh agentzh at gmail.com
Tue Jan 26 13:20:53 MSK 2010


Hi, folks!

I'm delighted to announce the first release of our new module,
ngx_xss. This output filter module adds native support for simple
cross-site AJAX to the nginx server. Currently only cross-site GET is
implemented, but cross-site POST support is on our TODO list.

Here's a small example using our ngx_echo module together:

    location /foo {
        default_type "application/json";
        echo '{"errcode":400,"errstr":"Bad Request"}';

        xss_get on; # enable cross-site GET support
        xss_callback_arg callback; # use $arg_callback
    }

Then accessing /foo?callback=blah gives the following response:

    blah({"errcode":400,"errstr":"Bad Request"}
    );

And the ultimate response Content-Type is set to
"application/x-javascript", which can be overridden by the
"xss_output_type" directive like this

    xss_output_type text/javascript;

By default, the ngx_xss module filter will skip responses with
Content-Type set to anything other than "application/json". If that's
not what you want, you can use the "xss_input_types" directive to
override that:

    xss_input_types text/plain text/css;

This module can also be chained with other output filters like ngx_rds_json:

    xss_get             on;
    xss_callback_arg    _callback;

    location /query {
        drizzle_query "select name from products limit 0, 10";
        drizzle_backend my_mysql;

        rds_json on;
    }

Then you can expect something like this when doing GET
/query?_callback=OpenResty.callback[32]

    OpenResty.callback[32]([{"name":"Bike"},{"name":"Book"}]);

Be careful with the order of output filters while building nginx. The
ngx_rds_json filter expects a valid binary stream in the RDS format
while the ngx_xss filter expects some JSON text. If you don't take the
order right, you'll see your ngx_xss settings get completely ingored
in the final responses. Because the ngx_xss filter sees RDS first and
it ignores it due to its "application/x-resty-dbd-stream" content
type.

Below is the correct nginx configure command if you want to use
ngx_xss and ngx_rds_json together:

    ./configure \
          --add-module=/path/to/xss-nginx-module \
          --add-module=/path/to/rds-json-nginx-module \
          # more options omitted here...

You see, the order of adding output filters on the configure time is
just the *reversed* order that the output filters are actually applied
at runtime. Generally speaking, the nginx output filter chain is a
stack, not a queue ;)

Only a very limited set of callback values is allowed to prevent
JavaScript injection. Valid callback values can be expressed using the
following (Ragel) grammar:

        identifier = [$A-Za-z] [$A-Za-z0-9_]*;

        index = [0-9]* '.' [0-9]+
              | [0-9]+
              ;

        main := identifier ( '.' identifier )*
                  ('[' index ']')?

This is exactly the Ragel grammar used to generate the C validator
used by the ngx_xss module itself.

Sorry for writing long emails. Just be too lazy to write formal
documentation atm hence filling most of the docs into this
announcement :P

Enjoy!
-agentzh



More information about the nginx mailing list