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