关于 sql 拼接和 sql 注入的问题

2023-01-12 15:07:48 +08:00
 horou

如图

我使用的是 sql 拼接的方式实现的不同规则的排序,这个 query.order 是请求接口传过来的值,是一个枚举类型

按道理来说是只能传数字类型,传其他类型接口会报 400 错误

这种情况会有 sql 注入 的风险吗?

3338 次点击
所在节点    程序员
33 条回复
h0099
2023-01-12 21:28:08 +08:00
#19 @IvanLi127 phpdelusions.net/pdo/sql_injection_example 所举的例子就是典型的同时混用 字符串拼接 和 prepared statement 的传参插值以实现将用户输入用于无法作为 prepared statement 的传参插值的地方(原文例子中是用于 UPDATE ... SET 子句,现实中更常见的就是 SELECT ...子句的字段名,或是楼上 ORDER BY ...子句的字段名),所以字符串拼接是这的短板

#20 @IvanLi127 byte0x39=字符串 9 是 ASCII 里的,不论什么 EASCII 编码都不可能修改掉这个 0x39 对应 9 的关系(顶多像 SHIFT-JIS 那样把\改成¥),那么您所说的转了几手难道是传输给使用远古的 BCDIC 编码的环境里了吗?还是阁下直接在前端验证用户输入白名单,所以无法保证后端收到的就是 0x39 byte ?
815979670
2023-01-12 22:49:56 +08:00
如果想要完全避免注入问题,需要使用 sql 预编译,然后通过参数绑定的方式执行,把 SQL 和数据分开绝对不会有问题。
ToBeHacker
2023-01-12 23:00:10 +08:00
用 prepare sql 啊,这不专门用来解决这个问题的么,性能还好
h0099
2023-01-12 23:12:16 +08:00
#15 @h0099 所说的 `给 query builder 传入 raw 部分如 selectRaw(用户输入)`实际上就是
#21 的`同时混用 字符串拼接 和 prepared statement 的传参插值`
您可能会觉得我从来都没有做过 在 prepared statement 里又直接拼接了用户输入 的罪恶行径
但实际上 orm 的 query builder 通过抽象隔离使得您在使用其提供的 selectRaw()等 api 时也忘记了这实际上就是危险的拼接
horou
2023-01-12 23:14:40 +08:00
@ToBeHacker 我只是在个别规则比较多的参数数量不固定情况使用了这种方式,其他都是用的 pg $1 $2 这种方式传的参,如果我上面的情况用这种的话,需要重复写几个 sql ,感觉比较麻烦,所以就用了这种方式
horou
2023-01-12 23:27:06 +08:00
@h0099 大佬,我上面图片的例子感觉不是很恰当,我下面这张图上,我就是用 prepared statement 和拼接混用的情况,这种会有风险吗?

![Imgur]( )
h0099
2023-01-12 23:48:24 +08:00
您需要控制{}的插值也就是那个 id 变量的取值区间,如果他来自程序内部那还比较容易保证其合法(比如您 1 楼所说的`query.order 是请求接口传过来的值,是一个枚举类型`),如果是用户输入您必须得假定恶意对它做合适的过滤甚至白名单
IvanLi127
2023-01-13 01:39:34 +08:00
@h0099 字符编码这个我也不能多说什么,我也没深入研究字符编码的问题,大概是编码长度转换出问题之类的,反正我是不信上古代码里关于字符串的处理。
另外预处理语句解决不了的业务你咋能怪预处理。。。我只是回复别人说替换文本不安全而已,和 op 的问题没关系。
xuanbg
2023-01-13 06:49:49 +08:00
@h0099 你传入的字符串包含了;,并不在允许的规则之内。所以还是安全的。
horou
2023-01-13 09:41:35 +08:00
@h0099 我这个 id 是一个 i32 的数值类型,这种也需要过滤一些值吗
southwolf
2023-01-13 10:42:13 +08:00
@h0099 ChatGPT 机器人你好...
NewYear
2023-01-13 11:33:57 +08:00
某机器人坚持要用参数化绑定数据,经过多轮交流,终于愿意以拼接字符串的方式写,其实就是黑名单与白名单+类型判断。不知道黑名单的字符串够不够完整。


```C#
// 定义变量
int num = 1;
string str = "abc";
DateTime dateTime = DateTime.Now;

// 将变量转换为 SQL 语句中可以使用的字符串
string numStr = num.ToString();
string strStr = str.Replace("'", "''");
string dateTimeStr = dateTime.ToString("yyyy-MM-dd HH:mm:ss");

// 拼接 SQL 语句
string sql = "SELECT * FROM table WHERE num=" + numStr + " AND str='" + strStr + "' AND datetime='" + dateTimeStr + "'";

// 执行 SQL 语句
// ...
```
NewYear
2023-01-13 11:34:30 +08:00
准确的说是转义符+类型判断

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/908431

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX