本文翻译自《Avoiding SQL injection risk》。
你可以通过提供SQL参数值作为sql
包里函数的参数来避免SQL注入风险。sql
包中的许多函数为SQL语句(包括准备语句)的参数提供参数值。
以下示例中的代码使用?
作为SQL语句的参数的占位符,由Query
函数的id
参数提供值:
// 使用参数执行一个SQL语句的正确格式
rows, err := db.Query("SELECT * FROM user WHERE id = ?", id)
执行数据库操作的sql
包的函数根据你提供的参数创建SQL准备语句。在运行时,sql
包将SQL语句转换为准备语句并将其与参数分开发送。
注意:参数占位符因你使用的DBMS和驱动程序而异。例如,Postgres的pq驱动程序使用$1
形式的占位符形式,而不是?
号。
你可能想使用fmt
包中的函数将SQL语句组装为包含参数值的字符串——如下所示:
// 有安全风险!
rows, err := db.Query(fmt.Sprintf("SELECT * FROM user WHERE id = %s", id))
这不安全!执行此操作时,Go会组装整个SQL语句,在将完整语句发送到DBMS之前用参数值替换%s
格式动词。这会带来SQL注入风险,因为代码的调用者可能会发送意外的SQL片段作为id
参数。该片段可能会以不可预测的方式执行SQL语句,这对你的应用程序是危险的。
例如,通过传递一个特定的%s
值,你可能会得到类似于以下内容的SQL语句,它可能会返回数据库中的所有用户记录:
SELECT * FROM user WHERE id = 1 OR 1=1;