多字符清理不完整¶
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
清理不受信任的输入是防止注入攻击和其他安全漏洞的常用技术。正则表达式通常用于执行此清理。但是,当正则表达式匹配多个连续字符时,仅替换一次会导致不安全文本在清理后的输入中重新出现。
攻击者可以通过精心构造的输入来利用此问题,这些输入在使用无效的正则表达式清理后,仍然包含恶意代码或内容。这会导致代码执行、数据泄露或其他漏洞。
建议¶
为了防止此问题,强烈建议尽可能使用经过良好测试的清理库。这些库更有可能处理极端情况并确保有效的清理。
如果库不是选项,您可以考虑其他策略来解决此问题。例如,重复应用正则表达式替换,直到无法再进行替换,或者重写正则表达式以匹配单个字符而不是整个不安全文本。
示例¶
考虑以下旨在删除所有 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
参考资料¶
OWASP Top 10: A1 注入.
Stack Overflow: 使用 JS 正则表达式从 HTML 中删除所有脚本标签.
常见弱点枚举:CWE-20.
常见弱点枚举:CWE-80.
常见弱点枚举:CWE-116.