首页 > 解决方案 > 使用 go-sql-driver 和 mysql 安全插入查询

问题描述

我已经使用 db.Prepare 查看了 go-sql-driver 示例,但我无法使其正常工作,因此我将其修改为直接使用 db.Query。我的理解是使用 ?? 无论如何,该值都被转义了,所以我想知道以下内容是否正确并且可以防止 SQL 注入(请注意,我使用的是 MySQL)

stmtIns, err := db.Query("INSERT INTO users (name, address) VALUES(?,?)", name, address) // ? = placeholder
        if err != nil {
            panic(err.Error()) // proper error handling instead of panic in your app
        }
        defer stmtIns.Close() // Close the statement when we leave main() / the program terminates

另外,检测是否已插入行的最佳方法是什么?

澄清:为了安全,我指的是 SQL 注入。我认为是这样,但后来我想知道为什么我能找到的所有示例都使用 db.Prepare 而不是 db.Query 。

标签: go

解决方案


是的,这可以避免 SQL 注入攻击。

请注意,客户端代码不会此类查询中“转义”参数。它做了一些更简单、更安全的事情:

客户端并没有将INSERT INTO users (name) VALUES(?)参数组合;DROP TABLE USERS;INSERT INTO users (name) VALUES(;DROP TABLE USERS;.

客户端也没有使用转义字符执行上述操作以使其“安全”。客户不构造类似的东西INSERT INTO users (name) VALUES("\;DROP TABLE USERS\;")

它所做的是向 MySQL 发送一个查询,其中分别包含:

  • 查询字符串INSERT INTO users (name) VALUES(?)——MySQL 知道这是一个查询字符串,并且知道这?是插入参数的位置。
  • 参数;DROP TABLE USERS;-- MySQL 知道这是查询的参数

因此,服务器知道参数不是 SQL 代码,这巧妙地避免了转义字符的整个讨厌的问题。

通过选择不使用Prepare,您正在跳过一些优化服务器的潜力。服务器将每个语句编译成内部表示,这需要时间。通过使这个显式并重新使用准备好的语句,您显式地节省了重复该编译步骤。

但是,MySQL 会缓存已编译的语句,以避免重复编译完全相同的字符串——因此您可能不会看到大的性能问题。


推荐阅读