避免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会在将完整的语句发送到DBMS之前,组装整个SQL语句,用参数值替换%s
格式动词。这会带来SQL注入风险,因为代码的调用者可能会将意外的SQL片段作为id
参数发送。该片段可能会以对您的应用程序危险的不可预测的方式完成SQL语句。
例如,通过传递特定的%s
值,您最终可能会得到类似以下的内容,这可能会返回数据库中的所有用户记录:
SELECT * FROM user WHERE id = 1 OR 1=1;