8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

AH10411 错误:空格和 %20 导致 Apache mod_rewrite 出现 403 禁止访问

Abhay Sharma 1月前

51 0

我今天更新了 Apache(至 2.4.56-1),以前可以正常工作的大量 .htaccess 重写现在出现 AH10411 错误,与查询中的空格有关。我正在寻找“正确”的解决方案……

我今天更新了 Apache(至 2.4.56-1),以前可以正常工作的大量 .htaccess 重写现在都收到 AH10411 错误,与查询中的空格有关。我正在寻找“正确”的解决方案。

用户点击一个链接,如 <a href='FISH%20J12345.6-78919'>clickme</a> 你所见,链接 URL 中的空格已被编码为 %20 .

相关服务器目录中的文件包含并执行该相关指令 .htaccess

RewriteRule ^(FISH\s*J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1 [L,QSA]

(在上面,我检查的是空格,而不是 %20 ,因为浏览器似乎在满足此规则之前将其转换为空格)。

在我更新 Apache 之前,这个功能一直有效;现在用户收到 403 错误,并且我的 Apache 错误日志报告:

AH10411:重写的查询字符串包含控制字符或空格

这似乎是一个新的错误,因为用谷歌搜索没有找到任何结果!

编辑我的页面(例如)将空格更改为下划线并正确处理它实际上不是一个选择,因为设计旨在支持用户能够使用他们关心的对象的名称直接输入 URL。到目前为止,我发现的唯一解决方法有点丑陋,即在正则表达式中分别捕获源名称的两个部分,因此:

RewriteRule ^(FISH)\s*(J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1+$2 [L,QSA]
                  ^   ^                                               ^^^

(我 $1%20$2 最后尝试了一下,也出现了同样的错误。)

有没有更好的解决方案?例如,当我想要捕获 URL 中的空格并将其作为参数传递给底层页面时,我应该如何处理它?

帖子版权声明 1、本帖标题:AH10411 错误:空格和 %20 导致 Apache mod_rewrite 出现 403 禁止访问
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Abhay Sharma在本站《.htaccess》版块原创发布, 转载请注明出处!
最新回复 (0)
  • J.J 1月前 0 只看Ta
    引用 2

    '我最后尝试了 $1%20$2,但结果也很糟糕\' ——我认为这产生了同样的错误?

  • 我在本地主机上遇到了完全相同的问题,在正在开发的版本上。托管很好。几天前一切都运行良好,然后突然出现了这样一个混蛋 :( Google 和你帮助了我。

  • (我最后尝试了 $1%20$2,但结果也很糟糕)。

    这看起来像是一个错误。将 空格 %20 查询字符串中的形式应该是有效的。您也可以将 空格 + 查询字符串中的形式(如您的解决方法中所述)。

    在您的原始规则中,Apache 在进行内部重写时应该将空格编码为 %20 (因为文字空格在 URL 中无效)。但是,Apache 似乎对编码空格犹豫不决(或者在重写中不自动编码 URL)?!

    您可以尝试 B 在原始规则中使用标志。该 B 标志告知 mod_rewrite 在将其应用于 替换 字符串之前对反向引用进行 URL 编码。但是,这似乎取决于 Apache 对 + 查询字符串中的空格进行编码(而不是 %20 通常的做法)。当然,在早期版本的 Apache 中,这只会导致 Apache 将空格编码 %20 不要 + ),但是,自 2.4.26 版以来,Apache 引入了一个新标志 BNP ( backrefnoplus ),它明确告知 Apache not 使用 + ,因此您会认为默认情况下它会使用 + 。(不幸的是,我现在无法自己测试。)

    例如:

    RewriteRule ^(FISH\s*J[\d.]+-?\+?\d+)$ myPage.php?sourceName=$1 [B,QSA,L]
    

    (小问题...在正则表达式字符类中使用时,不需要使用反斜杠转义文字点。我还将数字范围缩小为简写 \d 。)

    另外: 最后一组数字(用子模式表示)前 - 可以同时有 + -?\+? 吗?看起来应该是其中一个(或者什么都没有)?例如。 [-+]? .

    有没有更好的解决方案?例如,当我想要捕获 URL 中的空格并将其作为参数传递给底层页面时,我应该如何处理它?

    并非如此(尽管您的解决方案并不完全正确 明确 见下文)。在您的特定示例中,它仅包含 空格 ,您不需要 执行任何操作,因为 mod_rewrite 应该自动对任何无效的 URL 进行 URL 编码。(有一个 - NE - noescape 阻止 mod_rewrite 执行此操作 - 有时有必要防止已编码的字符被重复编码。)您始终可以 B 在这种形式的 URL 重写中使用该标志(如上所述)。 如果存在其他特殊字符,例如 需要 B 使用该 & ,否则这些字符不会被 URL 编码(实际上导致 URL 参数值被截断)。

    RewriteRule ^(FISH)\s*(J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1+$2 [L,QSA]
    

    请求中 有 0 个(即 \'none\')或更多 空格 空格 。这与您的原始指令不同,原始指令会保留原始请求中的空格(或缺少空格)。

    初始请求中是否可以有 0 个或更多空格?

    如果是,并且需要保留这些,那么重复此规则可能更容易,因为您需要尽可能多的“空格”。您可以实施搜索/替换,但这可能有点过头了。

    (在上面我检查的是空格,而不是 %20,因为浏览器似乎在遵守此规则之前将其转换为空格)。

    模式 RewriteRule 的 URL 路径 首先进行 URL 解码(% 解码),这就是为什么您需要匹配文字 空格 而不是 %20 。这与 \'浏览器\' 无关。URL 路径中的 空格 %20 在离开浏览器/用户代理的 HTTP 请求中一样,否则它就是无效的。


    (更新)限制对非字母数字字符进行编码

    有一条评论(已 删除 ),其中用户还在 + URL 路径中传递了(文字加号),似乎希望将其按原样传递给查询字符串(通过内部重写),然后将其视为编码空格但是,使用 B 标志(如上所述)会导致文字 + 被 URL 编码为,从而 %2b 保留文字 + - 这通常是正确的行为。但是,如果 + 应按原样复制,从而在生成的查询字符串中将其视为编码 空格 (而不是文字 + ),那么您可以限制标志将编码的非字母数字字符 B (需要 Apache 2.4.26+)。即排除 + .

    例如,你可以将编码限制为空格 ? 。例如:

    RewriteRule ^(.+)$ index.php?query=$1 "[B= ?,L]"
    

    + 将不再在反向引用中编码,因此其在查询字符串中的特殊含义(作为编码 空格 )仍然适用。

    注意:您不能只编码 空格 (因为空格不能用作 B 标志值参数中的最后一个字符),因此需要附加 ? 字符。因此,标志参数需要用双引号括起来,因为 空格 是参数分隔符。

    参考:

    • https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag_b
    • Mod 重写。B 标志不适用于空格。AH10411:重写的查询字符串包含控制字符或空格
  • 在我的服务器中,添加 B 标志就足以解决这个问题,而这个问题确实似乎只是通过最新的 Apache 中的一个错误出现的:服务器版本:Apache/2.4.56 (cPanel) 服务器构建时间:2023 年 3 月 8 日 15:06:38

  • 谢谢!添加 B 标志已为我解决了这个问题。关于您的其他观点:我不记得为什么我没有使用 \d;我怀疑我复制了一条旧规则,该规则在某一时刻只允许 0-5...至于空格:\'正确\' ID 将始终有一个空格,但我故意允许用户输入带有/不带有空格的 URL。因此,您对我当前解决方案的批评完全有效,但在这种特定情况下,这并不重要。还有 +/- 问题:我需要一个 + 或 - 符号(但不是两个),所以您是对的,只需 [+-] 就更好了。在构建原始 rexep 时,我显然半睡半醒!

  • 我要感谢@MrWhite 的解释。添加 B 标志也为我解决了 Ajax 搜索功能的这个问题。谢谢 :)

  • g0r 1月前 0 只看Ta
    引用 8

    我们在最近修补的 RHEL 8 系统中遇到了类似的问题,该系统将 Apache 更新到 2.4.37-51。这个:RewriteRule ^foo/bar/(.*)$ https://example.com/ab?cd=search&ef=1&q=$1 [L] 当 $1 中有空格时停止工作,我认为编码为 %20。当触发上述重写时,我们使用 CloudFront 的站点会出现 CloudFront 错误。改用这个:RewriteRule ^foo/bar/(.*)$ https://example.com/ab?cd=search&ef=1&q=$1 [B,L,NE] 似乎可以解决这个问题。不再出现 CloudFront 错误,重定向有效,将空格编码为 + 或 %2b。谢谢 @MrWhite!

  • @SpecialMonkey \'将空格编码为 + 或 %2b\' - %2b 是文字 +(加号),而不是空格。在对 URL 查询字符串部分中的空格进行编码时,它需要是 + 或 %20。RewriteRule 模式匹配的 URL 路径已经过 URL 解码 - 这是问题所在,因为它捕获的是文字空格,而不是编码空格。

  • 这是最近的 安全修复 .

    apache2 (2.4.52-1ubuntu4.4) jammy-security; urgency=medium
    
      * SECURITY UPDATE: HTTP request splitting with mod_rewrite and mod_proxy
        - debian/patches/CVE-2023-25690-1.patch: don't forward invalid query
          strings in modules/http2/mod_proxy_http2.c,
          modules/mappers/mod_rewrite.c, modules/proxy/mod_proxy_ajp.c,
          modules/proxy/mod_proxy_balancer.c, modules/proxy/mod_proxy_http.c,
          modules/proxy/mod_proxy_wstunnel.c.
        - debian/patches/CVE-2023-25690-2.patch: Fix missing APLOGNO in
          modules/http2/mod_proxy_http2.c.
        - CVE-2023-25690
      * SECURITY UPDATE: mod_proxy_uwsgi HTTP response splitting
        - debian/patches/CVE-2023-27522.patch: stricter backend HTTP response
          parsing/validation in modules/proxy/mod_proxy_uwsgi.c.
        - CVE-2023-27522
    
     -- Marc Deslauriers <[email protected]>  Wed, 08 Mar 2023 12:32:01 -0500
    
    
  • 引用 11

    将 apache 更新到 Apache/2.4.56(Ubuntu 18.04 LTS)后,我仍然遇到这个问题(需要修复 B 标志)服务器构建时间:2023-03-09T07:33:59 我猜这个 ubuntu 版本没有获得 Apache2 安全更新补丁?

  • @user6096790 当服务器确实得到修复时,您所需要的就是 B 标志修复。

  • 引用 13

    调试 Apache(ErrorLog 带有 LogLevel rewrite:trace6)显示,调用

    /FISH%20J12345.6-78919
    

    RewriteRule ^(FISH\s*J[0-9\.]+-?\+?[0-9]+)$ myPage.php?sourceName=$1 [L,QSA]
    

    在 mod_rewrite 得到 %20 之前,它正确地将其解码为空格。并且 URL 被重写为

    'myPage.php?sourceName=FISH J12345.6-78919'
    

    查询参数中有一个空格,mod_rewrite 不再喜欢这个。

    实际上,mod_rewrite 和规则会发生两件事,例如

    RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
    

    首先解码 URL 的 PATH 部分(请注意 PATH 部分中的 + 是 +,而不是解码为空格)并传递给 mod_rewrite。然后将其放入 $1。原始 URL 的 QUERY 部分未解码,但合并到重写的 PATH 部分。然后将新 URL 交回 Apache。然后 php 解码 QUERY 参数。这导致 PATH 部分被双重解码,因为在重写的 URL 中它是一个 QUERY 参数。

    如果没有 [B],例如 /A%2520B/?a=b%2520c (%25 解码为 %) 将被重写 q=A%20B/&a=b%2520c 为 php 中的 "q" => "A B/", "a" => "b%20c" 。实际上,乍一看并不完全符合预期(至少到目前为止,我所期望的是 "q" => "A%20B/" )。

    因此,无论如何,使用 [B] 将 PATH 部分移动到 QUERY 参数可能是更好的选择,确保它只被解码一次。

    使用 [B], /A%2520B/?a=b%2520c 最终被重写为 q=A%2520B%2f&a=b%2520c 在 php 中作为 "q" => "A%20B/", "a" => "b%20c" 。 对我来说看起来更好。

    使用 [B],FISH 链接的编码方式如下 escaping backreference 'FISH J12345.6-78919' to 'FISH+J12345%2e6%2d78919' ,因此空格的编码是通过 +(而不是 %20)完成的。在 php 中,它会再次解码。

    我认为,对于单编码的 PATH 部分,在大多数情况下不使用 [B] 是可以的,很可能是因为 % 符号在 PATH 部分中用得不多。对我来说,使用 [B] 现在是更好的解决方案。

    有一个警告,这里其他地方已经回答过了:由于 + 在 PATH 部分有效,因此 /A+%2bB/ 传递给 mod_rewrite 为 A++B/ (因此第一个 + 保持为 + ),最后 q=A%2b%2bB%2f 在 php 中传递为 "q" => "A++B/" 。这无法克服,因为 + 在 PATH 部分和 QUERY 部分的处理方式不同。

  • [BCTLS] 标志与该标志类似 [B] ,但仅转义控制字符和空格字符。这是在未编码的情况下复制到查询字符串中时被拒绝的同一组字符。

    此标志在 2.4.57 及更高版本中可用。

    来源: https://httpd.apache.org/docs/2.4/rewrite/flags.html#flag_bctls

  • 这对我有用,之后 RewriteEngine on

    RewriteBase /
    
    RewriteRule ^(.*)\ (.*)$ /$1+$2 [L,R=301]
    
  • 引用 16

    这不是一个“解决方案”,充其量只是一种低效的解决方法。您应该更改底层应用程序中的 URL(您实际链接到的 URL)。(在不更改 URL 的情况下,最好使用其他答案中提到的 B 标志,以正确编码替换字符串中的空格。)

返回
作者最近主题: