避免 SQL 注入风险

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

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

// Correct format for executing an SQL statement with parameters.
rows, err := db.Query("SELECT * FROM user WHERE id = ?", id)

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

注意:参数占位符会根据您使用的 DBMS 和驱动程序而异。例如,Postgres 的 pq 驱动程序 接受 $1 这样的占位符形式,而不是 ?

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

// SECURITY RISK!
rows, err := db.Query(fmt.Sprintf("SELECT * FROM user WHERE id = %s", id))

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

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

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