潜在的不安全引用¶
ID: go/unsafe-quoting
Kind: path-problem
Security severity: 9.3
Severity: warning
Precision: high
Tags:
- correctness
- security
- external/cwe/cwe-078
- external/cwe/cwe-089
- external/cwe/cwe-094
Query suites:
- go-code-scanning.qls
- go-security-extended.qls
- go-security-and-quality.qls
构造包含用户提供数据的带引号字符串字面量的代码需要确保此数据本身不包含引号。否则,嵌入的数据可能会(意外地或故意地)过早地终止字符串字面量,从而更改整个字符串的结构,并可能导致严重的后果。例如,如果稍后将该字符串用作操作系统命令或数据库查询的一部分,则攻击者可能会制作注入恶意命令的输入数据。
建议¶
适当地清理嵌入的数据,以确保对引号进行转义,或者使用不依赖于手动构造带引号子字符串的 API。确保使用适当的转义机制,例如,对 SQL 字符串使用双引号或对 shell 命令使用反斜杠转义。使用反斜杠转义时,还必须对反斜杠字符本身进行转义。
示例¶
在以下示例中,假设 version
是来自不受信任来源的对象。代码片段首先使用 json.Marshal
将此对象序列化为字符串,然后将其嵌入到使用 Squirrel 库构建的 SQL 查询中。
package main
import (
"encoding/json"
"fmt"
sq "github.com/Masterminds/squirrel"
)
func save(id string, version interface{}) {
versionJSON, _ := json.Marshal(version)
sq.StatementBuilder.
Insert("resources").
Columns("resource_id", "version_md5").
Values(id, sq.Expr(fmt.Sprintf("md5('%s')", versionJSON))).
Exec()
}
请注意,JSON 编码不会以任何方式转义单引号,因此此代码容易受到攻击:version
中的任何单引号字符都会过早地关闭周围的字符串字面量,从而更改正在构造的 SQL 表达式的结构。这可能会被利用来发动 SQL 注入攻击。
要修复此漏洞,请使用 Squirrel 结构化 API 中用于构建查询的占位符语法,这避免了显式构造带引号字符串的需要。
package main
import (
"encoding/json"
sq "github.com/Masterminds/squirrel"
)
func saveGood(id string, version interface{}) {
versionJSON, _ := json.Marshal(version)
sq.StatementBuilder.
Insert("resources").
Columns("resource_id", "version_md5").
Values(id, sq.Expr("md5(?)", versionJSON)).
Exec()
}
在结构化 API 不适用的情况下,请确保在将用户提供的数据嵌入到带引号的字符串中之前对引号进行转义。例如,以下是使用 strings.ReplaceAll
对单引号进行反斜杠转义的方法
quoted := strings.ReplaceAll(raw, `\`, `\\`)
quoted = strings.ReplaceAll(quoted, "'", "\\'")
请注意,必须先对字符串中任何现有的反斜杠字符进行转义,以便它们不会干扰单引号的转义。
在某些情况下,strconv.Quote
是反斜杠转义的便捷选择,但请注意,它有两个限制
它仅支持双引号,不支持单引号(如示例中所示)。
它将整个字符串括在引号中,因此只能用于构造完整的字符串字面量,而不能用于构造较大字符串字面量的一部分。