Exec和Raw
Exec
Exec
方法用于执行原生 SQL 语句,并且可以返回 SQL 执行的结果。这个方法通常用于执行更新、删除或执行存储过程等操作。
result := DB.Exec("UPDATE users SET age = ? WHERE name = ?", 22, "John")
rowCount, err := result.RowsAffected() // 获取受影响的行数
if err != nil {
// 处理错误
}
fmt.Println("Affected rows:", rowCount)
Raw
Raw
方法用于构建并执行原生 SQL 查询,它返回一个 *sql.Rows
结果集,你可以遍历这个结果集来获取查询的数据。
rows, err := DB.Raw("SELECT name, age FROM users WHERE age > ?", 18).Rows()
if err != nil {
// 处理错误
}
defer rows.Close() // 确保关闭结果集
var name string
var age int
// 遍历 rows 来获取每一行的数据
for rows.Next() {
err := rows.Scan(&name, &age)
if err != nil {
// 处理错误
}
fmt.Println("Name:", name, "Age:", age)
}
但是注意了,这两个语句都有被进行SQL注入攻击的风险,例如:
username := "user_input" // 假设这是从请求中获取的用户输入
password := "pass_input" // 假设这是从请求中获取的用户输入
// 错误示范:直接拼接用户输入
sql := "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'"
// 执行SQL查询...
//如果用户输入如下:
username: 'admin'; DROP TABLE users; --
password: 'password'
// 拼接完的语句就变成了
SELECT * FROM users WHERE username = 'admin'; DROP TABLE users; --' AND password = 'password'
为什么会可能被SQL注入攻击:
- 直接拼接用户输入:如果用户输入直接拼接到SQL语句中,攻击者可以输入恶意SQL代码,导致应用程序执行非预期的SQL命令。
- 缺乏输入验证:应用程序没有正确验证用户输入,或者验证机制不够强大,使得攻击者可以绕过输入限制。
- 使用动态SQL:动态构建SQL语句时,如果没有使用参数化查询或适当的转义机制,就可能导致SQL注入漏洞。
- 这些方法执行的是原生 SQL,所以它们不会受到 GORM 的钩子(callbacks)和中间件的影响。
- 当你使用
Raw
方法时,确保在最后调用rows.Close()
来关闭结果集,避免内存泄漏。
因此最好少一些使用 Exec
和 Raw
去进行操作数据库数据,而是采用参数化查询来防止 SQL 注入攻击,GORM 会将用户输入作为参数绑定到 SQL 语句中,而不是直接拼接到 SQL 字符串中。这种方法确保了用户输入不会被解释为 SQL 代码的一部分。
参数化查询的工作原理:
参数化查询使用占位符(如问号?
)来表示查询中的变量部分,然后将这些占位符的安全值在查询执行时传递给数据库。数据库驱动接管这些值,并确保它们正确地转义,以防止它们被作为 SQL 代码执行。
结构体化
GORM结构体化也可以有效的避免SQL注入,应尽量避免直接用SQL语句来执行增删改查。
例如:err = db.Where(clause.Gte{Column: clause.Column{Name: "id"}, Value: 1}).First(&u1).Error
这里用了 clause.Gte
结构体,里面通过 clause.Column
来加入我们要查询的字段,Value则为值,Gte
的意思是大于等于,同理还有Eq
(等于)、Gt
(大于)、Lt
(小于)、Lte
(小于等于)等结构体,用于查询。
这样做既预防了SQL注入的风险,也通过结构体化将id
这个字段加上了双引号作为SQL语句的查询限制条件,有效的避免了一些数据库id
字段为特殊字段不给使用的情况。
评论(0)