避免 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;