最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何解决在存储过程中执行EXEC(@sql)产生的二次注入问题?
时间:2026-07-01 09:44:57 编辑:袖梨 来源:一聚教程网
EXEC(@sql)是二次注入高危入口,因其直接执行字符串而不区分结构与数据,即使从数据库读取的字段含恶意代码也会被执行;必须改用sp_executesql并确保模板无值、类型显式声明、参数带等号传入,动态对象名需白名单校验,读库数据须重检。
为什么 EXEC(@sql) 是二次注入的高危入口
因为 EXEC 会把整个字符串当作 SQL 命令直接执行,数据库不区分“结构”和“数据”。哪怕你从数据库里取出的是一个看似普通的用户名字段,只要它含 ' OR 1=1 -- 这类内容,拼进 @sql 后就立刻变成可执行代码。
典型错误写法:EXEC('SELECT * FROM users WHERE name = ''' + @name + '''') —— 这里 @name 来自数据库查询结果,而你没做任何隔离处理。
- 哪怕
@name是从sys.tables查出来的,也不能默认可信 -
QUOTENAME()只防单引号闭合,挡不住]; DROP TABLE x; --这种结尾注入 - 所有拼接进
@sql的变量,无论来源(用户输入、数据库读取、配置表),都必须视为不可信
必须改用 sp_executesql,且参数绑定要完整
sp_executesql 不是“用了就行”,它只在三要素齐全时才真正起作用:SQL 模板不含值、参数类型显式声明、参数值独立传入。
正确写法分三段:
DECLARE @sql NVARCHAR(MAX) = N'SELECT * FROM users WHERE status = @status AND created_at > @since';DECLARE @params NVARCHAR(MAX) = N'@status TINYINT, @since DATETIME2(0)';EXEC sp_executesql @sql, @params, @status = 1, @since = '2024-01-01';
-
@sql中不能出现任何变量值,只允许@param占位符 -
@params字符串必须写全类型,@status TINYINT不能简写成@status - 第三个参数列表必须带等号,
@status = 1,不是1或@status - 如果参数是字符串,长度也要约束,比如
@name NVARCHAR(50),避免 MAX 类型绕过校验
动态对象名(表名/列名)必须白名单校验
SQL Server 不允许把表名、列名当参数传,硬拼就是唯一路径——但这条路必须加锁。
错误做法:SET @sql = 'SELECT * FROM ' + QUOTENAME(@table_name) —— QUOTENAME 只转义括号和引号,不验证合法性。
- 查系统视图确认存在且归属预期 schema:
IF NOT EXISTS (SELECT 1 FROM sys.tables t JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE s.name = 'dbo' AND t.name = @table_name) - 排序字段等走硬编码白名单:
IF @sort_col NOT IN ('id', 'created_at', 'status') THROW 50000, 'Invalid sort column', 1 - 别用
OBJECT_ID(@table_name)单独判断——它不校验 schema,恶意输入如users; DROP TABLE logs; --可能被截断后误判为合法
从数据库读出的数据再进查询前,必须重校验
二次注入的核心陷阱,就是开发者认为“已入库 = 已消毒”。但数据库只是存储容器,不负责语义安全。
- 哪怕数据来自内部管理后台录入,也要按输入规则重新校验:长度、字符集、正则模式(如
@name NOT LIKE '%[^a-zA-Z0-9_]%') - 数字类参数开头加范围检查:
IF @user_id < 1 OR @user_id > 999999 RETURN - 禁止在过程里做
CAST(@input AS NVARCHAR)或CONVERT后再拼接——转换失败报错,成功后可能已失真或绕过前期校验 - 如果业务逻辑确实需要拼接(如动态 WHERE 条件),应拆成多个预定义分支,而不是靠字符串拼接兜底
最危险的不是不知道要防,而是以为用了 sp_executesql 就万事大吉。参数类型太宽、对象名校验缺失、读库数据未经重检——任何一个环节松动,都等于给二次注入留了后门。
相关文章
- 明末渊虚之羽版本奖励错误如何补偿 07-01
- 原神峡谷盈月之镜解谜方法 07-01
- 末日进化如何升级人物卡 07-01
- 魔兽世界卡格罗什的命运背包位置在哪 07-01
- 沙石镇时光体力恢复方法大全 沙石镇时光快速回满体力的实用技巧 07-01
- 空洞骑士寻神者篇章攻略 07-01