路径表达式中使用不受控制的数据¶
ID: rb/path-injection
Kind: path-problem
Security severity: 7.5
Severity: error
Precision: high
Tags:
- security
- external/cwe/cwe-022
- external/cwe/cwe-023
- external/cwe/cwe-036
- external/cwe/cwe-073
- external/cwe/cwe-099
Query suites:
- ruby-code-scanning.qls
- ruby-security-extended.qls
- ruby-security-and-quality.qls
使用从用户控制的数据构建的路径访问文件可能会使攻击者访问意外资源。这可能导致敏感信息被泄露或删除,或者攻击者能够通过修改意外文件来影响行为。
建议¶
在使用用户输入构建文件路径之前,对其进行验证,可以使用 Rails 中的 ActiveStorage::Filename#sanitized
等现成库,也可以执行自定义验证。
理想情况下,请遵循以下规则
不允许超过一个“.”字符。
不允许目录分隔符,例如“/”或“\”(取决于文件系统)。
不要仅仅依靠替换“../”等有问题的序列。例如,在将此过滤器应用于“…/…//”后,结果字符串仍然是“../”。
使用已知良好模式的白名单。
示例¶
在第一个示例中,文件名从 HTTP 请求中读取,然后用于访问文件。但是,恶意用户可以输入一个绝对路径的文件名,例如 "/etc/passwd"
。
在第二个示例中,看起来用户被限制为打开 "user"
主目录中的文件。但是,恶意用户可以输入包含特殊字符的文件名。例如,字符串 "../../etc/passwd"
将导致代码读取位于 "/home/user/../../etc/passwd"
的文件,即系统的密码文件。然后,该文件将被发送回用户,让他们可以访问系统的所有密码。
class FilesController < ActionController::Base
def first_example
# BAD: This could read any file on the file system
@content = File.read params[:path]
end
def second_example
# BAD: This could still read any file on the file system
@content = File.read "/home/user/#{ params[:path] }"
end
end