存储过程本身不防SQL注入,关键在于参数是否强类型声明且不拼接字符串;动态对象名须白名单校验;xp_cmdshell等高危功能需禁用;应用层调用也必须参数化。

存储过程本身不防SQL注入,能防住的是你写法里有没有拼字符串。用 CREATE PROCEDURE 包一层,但内部还用 EXEC(@sql) 或 sp_executesql 拼接用户输入,等于给漏洞套了个马甲——该崩还是崩。
所有参数必须走强类型声明,且全程不参与字符串拼接
SQL Server 的参数化执行路径在存储过程里是默认启用的,前提是别手动破坏它。只要参数是通过 @param 声明、类型明确(比如 NVARCHAR(50))、长度可控,并在 WHERE/JOIN/ORDER BY 等子句中直接使用,SQL Server 就会把它当纯数据绑定,不会进语法解析阶段。
- ✅ 正确:
WHERE status = @status——@status是参数,不拼串,安全 - ❌ 危险:
WHERE status = ''' + @status + '''—— 单引号+拼接=提前闭合+代码执行 - ⚠️ 注意:
LEN(@status) > 50这类校验不能代替类型声明,它只防超长,不防恶意结构
真要动态表名或列名?必须白名单硬校验
业务极少需要运行时决定查哪张表,但一旦出现,EXEC 或 sp_executesql 就成了唯一选择。此时不能靠“过滤单引号”或“转义”,而要彻底堵死非法值入口。
- 用
IF @table_name NOT IN ('orders', 'users', 'products')显式比对,匹配不上就THROW - 避免用
CHARINDEX或正则模拟白名单,容易被绕过(比如'orders; DROP TABLE users--') -
QUOTENAME(@table_name)只负责加方括号和转义,不验证合法性,必须前置白名单
慎用 xp_cmdshell 和 sp_OAcreate,它们和注入无关但放大危害
这些系统存储过程不是SQL注入的成因,但一旦攻击者拿到执行权限(比如通过其他漏洞或弱口令),它们就是最顺手的后门工具。上线前必须确认:
-
xp_cmdshell默认禁用,检查是否被显式开启:SELECT value_in_use FROM sys.configurations WHERE name = 'xp_cmdshell' - 如果业务真需要调系统命令,改用 Windows 服务或消息队列解耦,而不是让数据库直连 shell
-
sp_OACreate属于 OLE 自动化,SQL Server 2022 默认关闭,且微软已标记为“即将弃用”,别碰
最容易被忽略的一点:存储过程再安全,也救不了调用它的应用代码。如果 C# 里用 string.Format("EXEC GetOrders @status = '{0}'", userInput) 构造 EXEC 语句,那存储过程里的所有防护都归零——外部传进来的 @status 已经是带单引号的恶意字符串了。

















