0

I'm trying to use Nginx Location to block requests similar to this, which are causing load issues with WordPress (and the multilingual WPML plugin):

GET /foo/bar/?s=/?s=/?s=/?s=/?s=/?s=/?s=/?s=/?s=/?s=/ HTTP/1.1

However simplifying it to the following doesn't match:

location ~* \?s= {
  return 404;
}

even though I've:

  • placed it above all other location directives
  • escaped the ?, but not the = (have tried that too)
  • removed ^ and $ to avoid slashes creating any confusion
  • used ~* for case-insensitive

(I can confirm that location foobar will correctly match "foobar" anywhere in the URL.)

2 Answers 2

1

The PCRE regex is correct. A test against Perl (the source of the Perl Compatible Regular Expressions) which are used by nginx according to the sources:

 perl -e 'print "yes\n" if "/foo/bar/?s=/?s=/?s=/?s=/?s=/?s=/?s=/?s=/?s=/?s=/" =~ m|\?s=/|'
  yes

The reason why it does not match is, that the location { } match only matches against the URL, not the URI (which includes the params).

So anything that follows after the ? will be ignored in the location match block.

The way to fix this is by useing the complete uri to match, not just the URL:

    if ( $request_uri ~ s=/ ) {
            return 404;
    }

Or if you want to include /foo/bar:

location /foo/bar { 
    if ( $request_uri ~ s=/ ) {
            return 404;
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

The location directive (as well as the rewrite directive) works with the normalized URI, which does not include the query part. You can't test the request query string using location or rewrite directives.

What you can do is check the $arg_s nginx variable:

if ($arg_s) {
    return 404;
}

However, this won't work if you have an empty s query argument in your request, e.g.:

GET /foo/bar/?s= HTTP/1.1

Alternatively, you can check whether the query string is present in the request at all using the $args variable:

if ($args) {
    return 404;
}

Or, use the following regular expression to block requests with the s query parameter, regardless of whether it is empty or not:

if ($args ~* (?:^|&)s=) {
    return 404;
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.