mod_rewrite 匹配编码的 URL

Posted

技术标签:

【中文标题】mod_rewrite 匹配编码的 URL【英文标题】:mod_rewrite match encoded URL 【发布时间】:2021-11-23 12:20:24 【问题描述】:

在我的 Apache 配置中,当查询字符串参数包含特定值时,我想返回 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'

谢谢

【问题讨论】:

【参考方案1】:

QUERY_STRING 服务器变量保持 % 编码(就像它在请求中一样),与 RewriteRule 模式 匹配的 URL 路径不同,后者是 % 解码的。

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

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,这可能有问题,也可能没有问题。要消除这种歧义并仅匹配查询字符串中的“key=value”对,那么您需要使用像 (?:^|&)mykey=myval(?:&|$) 这样的正则表达式。

【讨论】:

很好的使用expr指令 你是 Apache 忍者,谢谢 :) 我很好奇,开发人员是否有理由为这种情况保留查询字符串 %-encoded 而不是 RewriteRule 具有 %-decoded ?我意识到保持未转义的价值是“真实”价值,但一些针对网络管理员的“虚拟证明”保护措施可以帮助数百万人。常见场景:站点管理员想要阻止对 URL 的访问,但不知道恶意用户可以对查询字符串进行简单的 % 编码以绕过 RewriteCond

以上是关于mod_rewrite 匹配编码的 URL的主要内容,如果未能解决你的问题,请参考以下文章

PHP Mod_rewrite 和 URL 编码符号 - 只能使用其中一个,但不能同时使用?

在 mod_rewrite 规则正则表达式中匹配问号

Apache的Mod_rewrite学习(RewriteRule重写规则的语法) 转

Mod_rewrite 和 $_GET 变量

mod_alias 与 mod_rewrite 优先级

Mod_rewriting 将查询字符串写入 swf 文件