Saturday, April 9, 2022

[SOLVED] mod_rewrite match encoded URL

Issue

In my Apache config I'd like to return 403 when a query string parameter contains a specific value. Everything works fine except when the client query string is encoded in hex. How do I get it to match without having to type out the literal hex string?

RewriteEngine On
RewriteCond %{QUERY_STRING} mykey=myval [NC]
RewriteRule .* - [F,L]

Then test it:

# Works fine, returns 403
curl -I 'http://localhost/?mykey=myval'

# Does not work, returns 200:
curl -I 'http://localhost/?mykey=%6d%79%76%61%6c'
curl -I 'http://localhost/?%6d%79%6b%65%79=%6d%79%76%61%6c'

thx


Solution

The QUERY_STRING server variable remains %-encoded (as it is in the request), unlike the URL-path matched by the RewriteRule pattern, which is %-decoded.

However, on Apache 2.4 you can use an Apache expression with the RewriteCond directive to URL decode the QUERY_STRING before making the comparison. For example:

RewriteCond expr "unescape(%{QUERY_STRING}) =~ /mykey=myval/"
RewriteRule ^ - [F]

This will now successfully match requests of the form ?mykey=myval, ?mykey=%6d%79%76%61%6c and ?%6d%79%6b%65%79=%6d%79%76%61%6c.

You don't need the L flag when using F, since it is implied. The regex ^ is marginally more efficient than .* if you simply need to be successful for any URL-path (without actually matching anything).

Note that the regex mykey=myval matches that string anywhere in the query string, so it would successfully match anymykey=myval and mykey=myvalany, which may or may not be a problem. To remove that ambiguity and only match the "key=value" pair in the query string then you would need to use a regex like (?:^|&)mykey=myval(?:&|$) instead.



Answered By - MrWhite
Answer Checked By - Robin (WPSolving Admin)