CodeQL 文档

多字符清理不完整

ID: rb/incomplete-multi-character-sanitization
Kind: problem
Security severity: 7.8
Severity: warning
Precision: high
Tags:
   - correctness
   - security
   - external/cwe/cwe-020
   - external/cwe/cwe-080
   - external/cwe/cwe-116
Query suites:
   - ruby-code-scanning.qls
   - ruby-security-extended.qls
   - ruby-security-and-quality.qls

点击查看 CodeQL 代码库中的查询

清理不受信任的输入是防止注入攻击和其他安全漏洞的常用技术。正则表达式通常用于执行此清理。但是,当正则表达式匹配多个连续字符时,仅替换一次会导致不安全文本在清理后的输入中重新出现。

攻击者可以通过精心构造的输入来利用此问题,这些输入在使用无效的正则表达式清理后,仍然包含恶意代码或内容。这会导致代码执行、数据泄露或其他漏洞。

建议

为了防止此问题,强烈建议尽可能使用经过良好测试的清理库。这些库更有可能处理极端情况并确保有效的清理。

如果库不是选项,您可以考虑其他策略来解决此问题。例如,重复应用正则表达式替换,直到无法再进行替换,或者重写正则表达式以匹配单个字符而不是整个不安全文本。

示例

考虑以下旨在删除所有 HTML 注释开始和结束标签的 Ruby 代码

str.gsub(/<!--|--!?>/, "")  

给定输入字符串“<!<!— comment —>>”,输出将是“<!– comment –>”,其中仍然包含 HTML 注释。

解决此问题的一种可能的解决方案是重复应用正则表达式替换,直到无法再进行替换。这确保了不安全文本不会在清理后的输入中重新出现,从而有效地删除了目标模式的所有实例

def remove_html_comments(input)  
  previous = nil  
  while input != previous  
    previous = input  
    input = input.gsub(/<!--|--!?>/, "")  
  end  
  input  
end  

示例

另一个例子是以下旨在删除脚本标签的正则表达式

str.gsub(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/, "")  

如果输入字符串是“<scrip<script>is removed</script>t>alert(123)</script>”,输出将是“<script>alert(123)</script>”,其中仍然包含一个脚本标签。

解决此问题的办法是重写正则表达式以匹配单个字符(“<” 和 “>”)而不是整个不安全文本。这简化了清理过程,并确保删除了所有潜在的不安全字符

def remove_all_html_tags(input)  
  input.gsub(/<|>/, "")  
end  

另一个可能的解决方案是使用流行的 sanitize gem。它保留了大多数安全的 HTML 标签,同时删除了所有不安全的标签和属性。

require 'sanitize'

def sanitize_html(input)
  Sanitize.fragment(input)
end

示例

最后,考虑使用正则表达式 /\.\.\// 的路径清理器

str.gsub(/\.\.\//, "")  

正则表达式试图从 str 中删除所有 /../ 的出现。这将无法按预期工作:例如,对于字符串 /./.././,它将删除中间的 /../ 的单个出现,但字符串的其余部分将变为 /../,这是我们要尝试删除的子字符串的另一个实例。

解决此问题的一种可能的解决方案是使用来自 Ruby Facets gem 的 File.sanitize 函数。该库专门设计用于处理路径清理,它应该处理所有极端情况并确保有效的清理

require 'facets'  
  
def sanitize_path(input)  
  File.sanitize(input)  
end  

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私