不完整的 URL 子字符串清理¶
ID: rb/incomplete-url-substring-sanitization
Kind: problem
Security severity: 7.8
Severity: warning
Precision: high
Tags:
- correctness
- security
- external/cwe/cwe-020
Query suites:
- ruby-code-scanning.qls
- ruby-security-extended.qls
- ruby-security-and-quality.qls
清理不可信的 URL 是防止攻击(如请求伪造和恶意重定向)的重要技术。通常,这是通过检查 URL 的主机是否在一组允许的主机中来完成的。
但是,将 URL 视为字符串并检查允许的主机之一是否为 URL 的子字符串,这很容易出错。恶意 URL 可以通过将允许的主机之一嵌入到意外位置来绕过此类安全检查。
即使子字符串检查没有在安全关键上下文中使用,当检查意外成功时,不完整的检查仍然可能导致不良行为。
建议¶
在执行主机值检查之前解析 URL,并确保检查能够正确处理任意子域序列。
示例¶
以下示例代码检查 URL 重定向是否将到达 example.com
域或其子域之一,而不是某个恶意站点。
class AppController < ApplicationController
def index
url = params[:url]
# BAD: the host of `url` may be controlled by an attacker
if url.include?("example.com")
redirect_to url
end
end
end
然而,子字符串检查很容易被绕过。例如,可以通过将 example.com
嵌入到路径组件中:http://evil-example.net/example.com
,或者在查询字符串组件中:http://evil-example.net/?x=example.com
。通过检查解析的 URL 的主机来解决这些缺点
class AppController < ApplicationController
def index
url = params[:url]
host = URI(url).host
# BAD: the host of `url` may be controlled by an attacker
if host.include?("example.com")
redirect_to url
end
end
end
这仍然不是一个充分的检查,因为以下 URL 会绕过它:http://evil-example.com
http://example.com.evil-example.net
。相反,请使用允许主机的明确白名单来确保重定向安全
class AppController < ApplicationController
def index
url = params[:url]
host = URI(url).host
# GOOD: the host of `url` can not be controlled by an attacker
allowedHosts = [
'example.com',
'beta.example.com',
'www.example.com'
]
if allowedHosts.include?(host)
redirect_to url
end
end
end
参考资料¶
OWASP: SSRF
OWASP: XSS 未验证的重定向和转发速查表.
常见弱点枚举: CWE-20.