从远程源重定向 URL¶
ID: rb/url-redirection
Kind: path-problem
Security severity: 6.1
Severity: error
Precision: high
Tags:
- security
- external/cwe/cwe-601
Query suites:
- ruby-code-scanning.qls
- ruby-security-extended.qls
- ruby-security-and-quality.qls
在未验证输入的情况下直接将用户输入合并到 URL 重定向请求中,可能会导致钓鱼攻击。在这些攻击中,毫无戒心的用户可能会被重定向到一个恶意网站,该网站看起来与他们打算访问的真实网站非常相似,但实际上由攻击者控制。
建议¶
为了防止不受信任的 URL 重定向,建议不要将用户输入直接放到重定向 URL 中。相反,在服务器上维护一个授权重定向列表;然后根据提供的用户输入从该列表中选择。
如果不可能,则应通过其他方式验证用户输入,例如,通过验证目标 URL 是否与当前页面位于同一主机上。
示例¶
以下示例显示了一个 HTTP 请求参数直接用于 URL 重定向,而没有验证输入,这会导致钓鱼攻击
class HelloController < ActionController::Base
def hello
redirect_to params[:url]
end
end
解决此问题的一种方法是在执行重定向之前,根据一组已知的固定字符串验证用户输入
class HelloController < ActionController::Base
VALID_REDIRECTS = [
"http://cwe.mitre.org/data/definitions/601.html",
"http://cwe.mitre.org/data/definitions/79.html"
].freeze
def hello
# GOOD: the request parameter is validated against a known list of URLs
target_url = params[:url]
if VALID_REDIRECTS.include?(target_url)
redirect_to target_url
else
redirect_to "/error.html"
end
end
end
或者,我们可以通过检查 URL 是相对的还是在已知的良好主机上,来检查目标 URL 是否不会重定向到不同的主机
require 'uri'
class HelloController < ActionController::Base
KNOWN_HOST = "example.org"
def hello
begin
target_url = URI.parse(params[:url])
# Redirect if the URL is either relative or on a known good host
if !target_url.host || target_url.host == KNOWN_HOST
redirect_to target_url.to_s
else
redirect_to "/error.html" # Redirect to error page if the host is not known
end
rescue URI::InvalidURIError
# Handle the exception, for example, by redirecting to a safe page
redirect_to "/error.html"
end
end
end
请注意,如上所述,上面的代码将允许重定向到 example.com
上的 URL,这虽然无害,但可能并非预期。您可以将自己的域(如果已知)替换为 example.com
来防止这种情况。
参考资料¶
OWASP: 未验证的重定向和转发速查表.
Rails 指南:重定向和文件.
通用弱点枚举:CWE-601.