CodeQL 文档

从用户输入创建的日志条目

ID: go/log-injection
Kind: path-problem
Security severity: 7.8
Severity: error
Precision: medium
Tags:
   - security
   - external/cwe/cwe-117
Query suites:
   - go-security-extended.qls
   - go-security-and-quality.qls

点击查看 CodeQL 存储库中的查询

如果未经处理的用户输入被写入日志条目,则恶意用户可能能够伪造新的日志条目。

如果用户提供了一些在显示日志输出时会被解释的字符的输入,则可能会发生伪造。如果日志显示为纯文本文件,则恶意用户可以使用换行符。如果日志显示为 HTML,则可以包含任意 HTML 来欺骗日志条目。

建议

在记录用户输入之前,应先对其进行适当的编码。

如果日志条目是纯文本,则应使用 strings.Replace 或类似方法从用户输入中删除换行符。还应注意,用户输入在日志条目中应清晰标记,并且恶意用户不能以其他方式造成混淆。

对于将以 HTML 格式显示的日志条目,应在记录之前使用 html.EscapeString 或类似方法对用户输入进行 HTML 编码,以防止伪造和其他形式的 HTML 注入。

示例

在以下示例中,用户提供的用户名使用日志记录框架进行记录,而无需任何清理。

package main

import (
	"log"
	"net/http"
)

// BAD: A user-provided value is written directly to a log.
func handler(req *http.Request) {
	username := req.URL.Query()["username"][0]
	log.Printf("user %s logged in.\n", username)
}

在下一个示例中,使用 strings.Replace 确保用户输入中不存在换行符。

package main

import (
	"log"
	"net/http"
	"strings"
)

// GOOD: The user-provided value is escaped before being written to the log.
func handlerGood(req *http.Request) {
	username := req.URL.Query()["username"][0]
	escapedUsername := strings.ReplaceAll(username, "\n", "")
	escapedUsername = strings.ReplaceAll(escapedUsername, "\r", "")
	log.Printf("user %s logged in.\n", escapedUsername)
}

参考

  • ©GitHub 公司
  • 条款
  • 隐私