【问题标题】:Space character not being matched by regex in .htaccess.htaccess 中的正则表达式不匹配空格字符
【发布时间】:2023-04-02 12:49:01
【问题描述】:

我想阻止任何包含使用 mod_rewite 或空 ID 的 ID 包含任何非数字字符的请求。我的.htaccess 文件中有以下规则:

RewriteCond %{QUERY_STRING} ID=(\d*[^\d&]+\d*)*(&|$)
RewriteRule .* - [F]

除了包含空格字符的请求之外,其他方法都有效。

GET /page.php?ID=5 5 HTTP/1.1

在我使用各种测试套件(如https://regex101.com/)时,两个5之间的空格字符被[^\d&]+成功匹配,但这种类型的请求仍然通过。

我需要改变什么?

(是的,在我的 PHP 中处理了错误的用户输入,所以它是否通过并不重要)

【问题讨论】:

  • 空格是使用%20在url中编码的,你为什么要担心这个?
  • 我相信你可以只使用ID=[0-9]*[^0-9&] 正则表达式。如果您不使用%1 / %2,则无需捕获任何内容。
  • @Andreykul 空间是为来自常规浏览器的请求编码的,是的,但这些是探测漏洞的请求。
  • @Wiktor Stribiżew 我也想屏蔽一个空 ID

标签: regex .htaccess mod-rewrite pcre


【解决方案1】:

也许这对你有用:

RewriteCond %{QUERY_STRING} !(?:^|&)ID=\d+(?:&|$)
RewriteRule ^ - [F]

如果您只希望它影响在查询字符串中具有 ID 参数的请求(因此允许没有 ID 的请求):

RewriteCond %{QUERY_STRING} (?:^|&)(?:\%(?:20|09))*ID(?:\%(?:20|09))*= [NC]
RewriteCond %{QUERY_STRING} !(?:^|&)ID=\d+(?:&|$)
RewriteRule ^ - [F]

我还添加了[NC](不区分大小写),这样iD 等也将被此覆盖。

【讨论】:

  • CondPattern中的参数名周围出现\s*是什么原因?我不一定会在 negated 条件中包含NC 标志。在 PHP 中,URL 参数名称区分大小写,因此 iD 等可能会更好地被阻止。 (?)
  • \s* 用于确保捕获所有指定 ID 的尝试,这是 OP 的主要关注点。似乎值得做?关于否定条件的 NC 的优点,已删除。
  • 但是\s* 可以匹配任何东西吗? QUERY_STRING 服务器变量是 URL 编码的,所以它不应该在有效请求中包含文字空白字符 - 并且任何格式错误的请求都应该被服务器阻止? \s* 对我来说似乎是多余的,但也许我错过了什么?只是好奇。 (+1)
  • 我正在研究 URL 在匹配之前被解码的理论,但只是经过测试,实际上没有。同意您的观点并已将其删除。
  • @user82217 我在 URL 编码空间或水平制表符上添加了一个匹配项来代替之前的 \s,尽管确实需要测试 Apache 是否允许通过以及 PHP 是否会忽略空间。
【解决方案2】:

@Andreykul 空格是为来自常规浏览器的请求编码的,是的,但这些是探测漏洞的请求。

可能是网络服务器本身的漏洞,而不是您的网络应用程序......(?)

GET /page.php?ID=5 5 HTTP/1.1

这个“问题”是它是一个无效/格式错误的请求。为了使其有效,它必须进行 URL 编码。 (文字)空格是请求第一行中的一个特殊字符,充当标头的“方法”、“请求-URI”和“HTTP-版本”部分之间的分隔符。

由于请求无效,因此可以合理地预期它已经在服务器级别被400 Bad Request 阻止。

如果服务器没有阻止请求,那么您可能会遇到意外行为。这可能就是你在这里看到的......

对于这样的请求,如果您检查QUERY_STRING 服务器变量,您会发现它不包含空格或第二个5。该值在文字空间之前被截断,它只包含ID=5。 (因此,这也是 PHP 所看到的。)因此,您的正则表达式 (CondPattern) 永远不会匹配。

但是,完整的请求 URI 存在于请求的第一行(正如您在上面发布的那样) - 这在 THE_REQUEST Apache 服务器变量中可用。最好简单地阻止任何包含文字空格的请求(无论如何都是无效),而不是专门搜索包含ID 参数的请求。例如:

RewriteCond %{THE_REQUEST} \s.*\s.*\s
RewriteRule ^ - [R=400]

这会检查外部空间分隔符之间包含的任何空白。

参考:
https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html

【讨论】:

  • 这是一个很好的答案,谢谢你,很好地看到了问题的根源。
  • 不错的解决方案:)
猜你喜欢
  • 1970-01-01
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 2017-06-28
  • 1970-01-01
相关资源
最近更新 更多