如何修复C#中Process.Start引发的OS命令行注入漏洞
你遗漏的核心防护点
正则规则引入了危险字符
你当前的正则^(?=.*[0-9])(?=.*[A-Za-z])(?=.*[!@#$%&*-+=^]).{12,}$明确允许&、|、^等CMD环境下的命令分隔/控制字符。由于bat文件的执行依赖CMD解析,哪怕你设置了UseShellExecute = false,CMD仍然会解析参数中的控制字符:攻击者可以构造符合正则规则的参数拼接额外命令,比如Test123456!&calc.exe完全匹配你的正则,但传入bat后&后的calc.exe会被CMD作为独立命令执行,直接触发注入。没有做参数结构转义/包裹
你直接将原始参数赋值给Process.StartInfo.Arguments,没有对参数做结构化处理:如果参数包含空格、双引号,会被CMD识别为多个参数甚至截断注入;即使参数没有危险字符,也可能因为参数结构被打破触发非预期行为。未校验bat文件本身的参数处理逻辑
即使你传入的参数本身安全,如果bat文件内部引用参数时没有用引号包裹,比如bat内写的是operate %1而非operate "%~1",攻击者仍然可以通过带引号的参数打断原有逻辑实现注入。边界判断缺失
你直接访问args[0]未判断命令行参数是否为空,虽然有全局异常捕获,但会导致非预期的程序崩溃,也可能被攻击者利用触发异常分支的潜在问题。
修复方案
- 收紧正则规则:移除所有CMD控制字符,仅保留业务必需的字符,示例(根据实际业务调整允许的特殊字符):
// 移除&、|、^、;、>、<等所有命令控制字符,仅保留业务需要的特殊符号 string complexityRules = @"^(?=.*[0-9])(?=.*[A-Za-z])(?=.*[!@#$%*]).{12,}$";
如果业务参数可选范围有限,优先用白名单匹配替代正则校验,安全性更高。
2. 参数结构化处理:将参数用双引号包裹,同时转义参数内部的双引号:
// 先判断参数数组非空再访问,避免索引越界 if (args.Length > 0 && args[0] != null) { // 包裹参数并转义内部双引号 string safeArg = $"\"{args[0].Replace("\"", "\"\"")}\""; proc.StartInfo.Arguments = safeArg; }
- 加固bat文件:bat内所有引用传入参数的位置,都用
"%~n"(n为参数序号)的格式,自动去掉参数外层引号后再用引号包裹,避免参数被截断:
@echo off :: 错误写法:echo %1 :: 正确写法 echo "%~1"
内容的提问来源于stack exchange,提问作者Karthik Karnam
相关产品推荐
相关产品推荐

