Apache升级至2.4.56-1后AH10411错误:含空格URL重写403求助
问题背景
升级Apache至2.4.56-1版本后,原本正常运行的大量.htaccess重写规则因URL中的空格触发AH10411错误,导致用户访问出现403禁止访问问题。
用户点击的链接示例为FISH%20J12345.6-78919(空格已编码为%20),相关服务器目录下的.htaccess规则如下:
RewriteRule ^(FISH\s*J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1 [L,QSA]
浏览器会将%20转换为空格后传递至规则,因此正则匹配的是空格而非%20。该规则在升级前可正常运行,升级后错误日志记录:
AH10411: Rewritten query string contains control characters or spaces
由于设计需求需支持用户直接输入关注对象的名称作为URL,无法通过修改页面将空格替换为下划线等方式解决。目前临时方案是拆分捕获组并用+连接:
RewriteRule ^(FISH)\s*(J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1+$2 [L,QSA]
(尝试使用$1%20$2时仍会触发相同错误)
标准处理方式
Apache 2.4.56+新增了对重写后查询字符串的严格校验,禁止直接传递未编码的空格。针对这类场景,有两种标准解决方案:
方法1:使用B标志自动编码反向引用
B(escape backreferences)标志会自动对重写规则中的反向引用进行URL编码,将空格转为%20,符合查询字符串规范,避免触发AH10411错误。修改原有规则如下:
RewriteRule ^(FISH\s*J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1 [L,QSA,B]
后端PHP通过$_GET['sourceName']可直接获取解码后的原始字符串(包含空格),无需额外处理。
方法2:手动编码空格并配合NE标志
如果需要更精细化控制,可手动将捕获到的空格替换为%20,同时使用NE(no escape)标志避免Apache对%20进行二次编码:
RewriteRule ^(FISH)(\s*)(J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1%20$3 [L,QSA,NE]
这种方式同样能确保后端正确获取到包含空格的原始参数值。
临时方案的原理
临时方案中用+连接两个捕获组,是因为在application/x-www-form-urlencoded格式的查询字符串中,+等价于空格,后端PHP会自动将+解析为空格,因此能正常工作,但这属于间接替代方案,并非标准的空格传递方式。
内容的提问来源于stack exchange,提问作者Phil Evans

