Space character does not match regex in .htaccess

I want to block any request containing an id containing any non-numeric character using mod_rewite or an empty id. I have the following rule in the file .htaccess

:

RewriteCond %{QUERY_STRING} ID=(\d*[^\d&]+\d*)*(&|$)
RewriteRule .* - [F]

      

Works except for queries containing whitespace, eg.

GET /page.php?ID=5 5 HTTP/1.1

      

The space character between the two 5s matches successfully with [^\d&]+

when I use various test packages (such as https://regex101.com/ ) but this type of request still gets through.

What do I need to change?

(yes, incorrect user input is handled in my PHP, so it doesn't matter if that gets through)

+3


source to share


3 answers


@ Andreykul spaces are coded for requests from regular browsers yes, but they are vulnerability checking requests.

Perhaps the vulnerabilities are in the web server itself and not in your web application ... (?)

GET /page.php?ID=5 5 HTTP/1.1

      

The "problem" is that this is a bad / invalid request. For this to be correct, it must be URL encoded. The (literal) space is a special character in the first line of the request and acts as a separator between the "Method", "Request-URI" and "HTTP-Version" header parts.

Since the request is invalid, it would be reasonable to expect that it will already be blocked at the server level with 400 Bad Request

.

If the server is not blocking the request, you are likely to encounter unexpected behavior. It is possible that you see here ...



For a query like this, if you examine the server variable QUERY_STRING

, you will see that it does not contain a space or a second 5

. The value is truncated before the literal space, it just contains ID=5

. (Hence, this is also what PHP sees.) So, your regex (CondPattern) never matches.

However, the complete URI request is present in the first line of the request (as you wrote above) - this is available in the THE_REQUEST

Apache server variable . It will probably be preferable to simply block any query that contains literal spaces (which is invalid anyway) rather than looking specifically for queries that contain a parameter ID

. For example:

RewriteCond %{THE_REQUEST} \s.*\s.*\s
RewriteRule ^ - [R=400]

      

This checks for any whitespace contained between the outer space delimiters.

Help:
https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html

+2


source


Maybe this will work for you:

RewriteCond %{QUERY_STRING} !(?:^|&)ID=\d+(?:&|$)
RewriteRule ^ - [F]

      

And if you want this to affect requests that have an ID parameter in the query string (so requests without an ID are allowed):



RewriteCond %{QUERY_STRING} (?:^|&)(?:\%(?:20|09))*ID(?:\%(?:20|09))*= [NC]
RewriteCond %{QUERY_STRING} !(?:^|&)ID=\d+(?:&|$)
RewriteRule ^ - [F]

      

I also added [NC]

(case insensitive) so iD

etc. will also be covered by this.

+3


source


use the following regex ID=\d+[&$]

-1


source







All Articles