mod_rewrite 匹配编码 URL

mod_rewrite match encoded URL

在我的 Apache 配置中,当查询字符串参数包含特定值时,我想 return 403。一切正常,除非客户端查询字符串以十六进制编码。如何在不输入文字十六进制字符串的情况下使其匹配?

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

然后测试一下:

# 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'

感谢

QUERY_STRING 服务器变量保持 % 编码(因为它在请求中),与 RewriteRule 模式匹配的 URL 路径不同,这是 %-解码的。

但是,在 Apache 2.4 上,您可以使用带有 RewriteCond 指令的 Apache 表达式来 URL 解码 QUERY_STRING,然后再进行比较。例如:

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

这将成功匹配 ?mykey=myval?mykey=%6d%79%76%61%6c?%6d%79%6b%65%79=%6d%79%76%61%6c.

形式的请求

使用 F 时不需要 L 标志,因为它是 隐含的 。正则表达式 ^.* 稍微更有效,如果你只需要对任何 URL 路径成功(实际上没有匹配任何东西)。

请注意,正则表达式 mykey=myval 匹配查询字符串中任何位置的该字符串,因此它会成功匹配 anymykey=myvalmykey=myvalany,这可能是问题,也可能不是问题。要消除这种歧义并仅匹配查询字符串中的“键=值”对,那么您需要使用 (?:^|&)mykey=myval(?:&|$) 之类的正则表达式。