路径表达式中使用不受控数据¶
ID: swift/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:
- swift-code-scanning.qls
- swift-security-extended.qls
- swift-security-and-quality.qls
访问由用户控制的路径可能会将资源暴露给攻击者。
从用户控制的数据中天真地构建的路径可能包含意外的特殊字符,例如 ..
。这样的路径可能指向文件系统上的任何目录。
建议¶
在使用用户输入来构建文件路径之前验证用户输入。理想情况下,请遵循以下规则:
不允许出现超过一个
.
字符。不允许使用目录分隔符,例如
/
或\
(取决于文件系统)。不要依赖于简单地替换
../
这样的问题序列。例如,将此过滤器应用于.../...//
后,结果字符串仍然是../
。使用已知良好模式的白名单。
示例¶
以下代码展示了两个不良示例。
let fm = FileManager.default
let path = try String(contentsOf: URL(string: "http://example.com/")!)
// BAD
return fm.contents(atPath: path)
// BAD
if (path.hasPrefix(NSHomeDirectory() + "/Library/Caches")) {
return fm.contents(atPath: path)
}
第一个示例从 HTTP 请求中读取文件名,然后使用该文件名来访问文件。在这种情况下,恶意响应可能会包含一个文件名,该文件名是一个绝对路径,例如 "/Applications/(current_application)/Documents/sensitive.data"
。
第二个不良示例中,用户似乎被限制在 "/Library/Caches"
主目录中打开文件。在这种情况下,恶意响应可能会包含一个文件名,该文件名包含特殊字符。例如,字符串 "../../Documents/sensitive.data"
将导致代码读取位于 "/Applications/(current_application)/Library/Caches/../../Documents/sensitive.data"
的文件,其中包含用户的敏感数据。然后,此文件可能被攻击者访问,从而使他们能够访问所有这些数据。
在以下(良好)示例中,用于访问文件系统的路径在与已知前缀进行检查之前被规范化。这确保了无论用户输入如何,结果路径都是安全的。
let fm = FileManager.default
let path = try String(contentsOf: URL(string: "http://example.com/")!)
// GOOD
let filePath = FilePath(stringLiteral: path)
if (filePath.lexicallyNormalized().starts(with: FilePath(stringLiteral: NSHomeDirectory() + "/Library/Caches"))) {
return fm.contents(atPath: path)
}