将逗号分隔字符串作为参数传入IN子句能否防范SQL注入?
这个IN子句用字符串参数的存储过程能防SQL注入吗?
先给结论:
- 防注入是能防,但这个写法逻辑完全错误,根本达不到你想要的多值筛选效果。
为什么逻辑错误?
当你把'1,3'这种逗号分隔的字符串传入@StatusCodes参数时,SQL Server会把整个字符串当成单一的搜索值,而不是拆成1和3两个值。也就是说,实际执行的是:
WHERE ActionStatusCode = '1,3'
而不是你期望的:
WHERE ActionStatusCode IN (1,3)
除非你的ActionStatusCode字段存的是类似'1,3'这样的字符串,否则这个存储过程查不出你要的结果。
关于SQL注入的安全性
这个写法用了参数化查询,所以不存在SQL注入风险。参数化查询会把@StatusCodes里的内容当成纯数据处理,不会解析其中的SQL语句。哪怕有人恶意传入'1'); DROP TABLE Action; --这种字符串,SQL Server也只会把它当作一个普通字符串去匹配ActionStatusCode字段,不会执行里面的DROP语句。
正确的实现方式
既然你想要便捷又安全的多值筛选,推荐两种常用方法:
1. 表值参数(推荐,高效且规范)
先创建一个自定义表类型:
CREATE TYPE StatusCodeList AS TABLE (StatusCode INT);
然后修改存储过程:
CREATE PROCEDURE CurrentActions @StatusCodes StatusCodeList READONLY AS SELECT ActionId, ActionName, ActionStatusCode, Comments FROM Action WHERE ActionStatusCode IN (SELECT StatusCode FROM @StatusCodes) GO
调用时直接传入包含多个状态码的表参数,这种方式是SQL Server官方推荐的多值传递方案,安全且性能好。
2. 使用STRING_SPLIT拆分字符串(适合SQL Server 2016+)
如果无法使用表值参数,可以用内置的STRING_SPLIT函数拆分逗号分隔的字符串:
CREATE PROCEDURE CurrentActions @StatusCodes nvarchar(100) AS SELECT ActionId, ActionName, ActionStatusCode, Comments FROM Action WHERE ActionStatusCode IN ( SELECT TRY_CAST(value AS INT) FROM STRING_SPLIT(@StatusCodes, ',') WHERE TRY_CAST(value AS INT) IS NOT NULL ) GO
这里用TRY_CAST是为了避免传入非数字字符串时报错,自动过滤无效值。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

