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)