日志注入¶
ID: js/log-injection
Kind: path-problem
Security severity: 6.1
Severity: error
Precision: medium
Tags:
- security
- external/cwe/cwe-117
Query suites:
- javascript-security-extended.qls
- javascript-security-and-quality.qls
如果未经清理的用户输入被写入日志条目,恶意用户可能会伪造新的日志条目。
如果用户提供了一些在显示日志输出时会被解释的字符作为输入,则可能会发生伪造。如果日志以纯文本文件形式显示,那么恶意用户可以使用换行符。如果日志以 HTML 形式显示,那么就可以包含任意 HTML 来伪造日志条目。
建议¶
用户输入在记录之前应进行适当清理。
如果日志条目为纯文本,则应使用 String.prototype.replace
或类似方法从用户输入中删除换行符。还应注意清楚地标记日志条目中的用户输入。
对于将在 HTML 中显示的日志条目,用户输入在记录之前应进行 HTML 编码,以防止伪造和其他形式的 HTML 注入。
示例¶
在第一个示例中,使用 `console.info` 记录用户提供的用户名。在第一种情况下,记录时没有任何清理。在第二种情况下,用户名用于构建一个使用 `console.error` 记录的错误。如果恶意用户提供 `username=Guest%0a[INFO]+User:+Admin%0a` 作为用户名参数,则日志条目将被分成两行,其中第二行为 `[INFO]+User:+Admin`。
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
let q = url.parse(req.url, true);
console.info(`[INFO] User: ${q.query.username}`); // BAD: User input logged as-is
})
server.listen(3000, '127.0.0.1', () => {});
在第二个示例中,String.prototype.replace
用于确保用户输入中不存在换行符。
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
let q = url.parse(req.url, true);
// GOOD: remove newlines from user controlled input before logging
let username = q.query.username.replace(/\n|\r/g, "");
console.info(`[INFO] User: ${username}`);
});
server.listen(3000, '127.0.0.1', () => {});