避免 SQL 注入风险

您可以通过提供 SQL 参数值作为sql包函数参数来避免 SQL 注入风险。sql包中的许多函数为 SQL 语句和要在该语句的参数中使用的值提供参数(其他函数为预处理语句和参数提供参数)。

以下示例中的代码使用?符号作为 id 参数的占位符,该参数作为函数参数提供:

// 使用参数执行 SQL 语句的正确格式.
rows, err := db.Query("SELECT * FROM user WHERE id = ?", id)

执行数据库操作的 sql 包函数从您提供的参数创建预处理语句。在运行时, sql 包将 SQL 语句转换为预处理语句,并将其与参数(单独的参数)一起发送。

注意: 参数占位符因您使用的 DBMS 和驱动程序而异。例如, Postgres 的 pq 驱动 接受占位符形式,例如 $1代替?

您可能很想使用fmt包中的函数将 SQL 语句组装为包含参数的字符串 – 如下所示:

// 安全风险!
rows, err := db.Query(fmt.Sprintf("SELECT * FROM user WHERE id = %s", id))

这不安全!执行此操作时,Go 会组装整个 SQL 语句,将%s格式动词替换为参数值,然后将完整语句发送到 DBMS。这会带来SQL 注入风险,因为代码的调用者可能会发送意外的 SQL 片段作为id参数。该片段可能以对您的应用程序危险的不可预测的方式完成 SQL 语句。

例如,通过传递某个%s值,您可能会得到类似以下的结果,这可能会返回数据库中的所有用户记录:

SELECT * FROM user WHERE id = 1 OR 1=1;