go-gorm / gorm

The fantastic ORM library for Golang, aims to be developer friendly
https://gorm.io
MIT License
36.66k stars 3.92k forks source link

DB.Model(&AAA{}).Order("if(user()='root@xxx.xxx.xxx.xxx', column_name, 1) desc").Offset(offset).Limit(pageSize).Scan(&list).Error,这种情况算不算sql注入? #7053

Open sun-xch opened 3 months ago

sun-xch commented 3 months ago

Your Question

The document you expected this should be explained

Expected answer

victor-zzh commented 3 months ago

有打印实际执行的sql吗。如果到了数据库层执行还存在敏感关键词那这就是注入了

ivila commented 3 months ago

算,不要把别人传过来的字符串内容直接用到SQL里面。

实际上防注入的方式是使用PrepareStatement去对你的SQL语句做预编译,然后再把参数写进去,保证参数只是参数。 比如你想用一个str field去做等值判断: 正确的写法:

    query := db.Model(Table{}).Where("field_str = ?", "random str").Where("id = ?", 1)

然后GORM底层会帮你使用prepare statement去防止注入

// 预编译生成一个Prepare Statement
PREPARE stmt1 FROM 'SELECT * FROM table_a WHERE field_str = ? AND id = ?';
// 然后使用参数去调用
set @a = 'random str';
set @b = 4;
EXECUTE stmt1 USING @a, @b;

你这种写法是错误的,因为你直接把用户输入拼接到SQL里面了,你就类似于做了这样的操作 错误的写法:

    query := db.Model(Table{}).Where(fmt.Sprintf("field_str = '%s'", "random str")).Where("id = ?", 1)

对应执行的SQL就是

// 预编译了一个已经完成SQL注入的SQL
PREPARE stmt1 FROM "SELECT * FROM table_a WHERE field_str = 'random str' AND id = ?";
// 然后使用参数去调用
set @b = 4;
EXECUTE stmt1 USING @b;

所以对于你的问题的答案:是的,你这么写是可能被SQL注入的,所以你一定要检查column_name必须是合法的输入(比如你自己搞个enum去限定之类的)

iseki0 commented 3 months ago

不止 Order,还有 Select,Table 等等,以及 Where 的第一个参数,就是用来注入 SQL 的,许多功能需要通过灵活拼接 SQL 实现,这个地方过滤注入就没法用了。这是 feature。