Fortify SCA标记C#存储过程调用代码存在SQL注入问题咨询
SQL注入风险分析与修复方案
被Fortify标记的原因
- 错误的输入清理方式:代码里用
Sanitizer.GetSafeHtmlFragment()处理存储过程名,这是用来清理HTML标签的工具,对数据库对象名的安全校验完全没用。攻击者传个带恶意构造的存储过程名,这个方法根本拦不住。 - 用户可控的存储过程名未做有效校验:虽然设置了
CommandType.StoredProcedure,但如果存储过程名是用户能随便传的,攻击者可以构造类似合法存储过程名; DROP TABLE 敏感表--的字符串,照样能触发SQL注入(某些数据库环境下,即使指定存储过程类型,恶意名称也可能被解析成多条执行语句)。 - Fortify规则触发逻辑:工具识别到用户输入直接用于生成SqlCommand的存储过程名,且使用了完全不匹配的清理手段,直接判定为SQL注入风险点。
修复方案
1. 用白名单机制校验存储过程名(最安全)
提前维护系统里所有合法的存储过程名列表,只有传入的名称在列表里才允许执行,否则直接报错。示例代码:
// 提前定义合法存储过程白名单 private static readonly HashSet<string> AllowedStoredProcs = new HashSet<string> { "GetUserInfo", "FetchOrderRecords", // 补充其他系统用到的存储过程名 }; public DataSet GetTableByStoredProc(string strProcName, ArrayList alParams) { // 先做白名单校验 if (!AllowedStoredProcs.Contains(strProcName)) { throw new ArgumentException("无效的存储过程名称"); } DataSet dataSet = new DataSet(); // 后续逻辑直接用strProcName,不需要HTML清理 // ...原有代码逻辑 }
2. 移除无效的HTML清理代码
删掉string SPname1 = Sanitizer.GetSafeHtmlFragment(strProcName);这行,它不仅防不住注入,还可能把合法的存储过程名搞坏(比如带下划线、特殊后缀的名称)。
3. 优化资源释放逻辑
原有代码finally块里的objConn.Dispose()和objCmd.Dispose()是多余的,因为objCmd已经在using里自动释放,objConn也应该用using包裹,避免资源泄漏:
try { using (SqlConnection objConn = new SqlConnection()) { GetConnection(ref objConn); // 假设这个方法负责设置连接串并打开连接 using (SqlCommand objCmd = new SqlCommand(strProcName, objConn)) { objCmd.CommandType = CommandType.StoredProcedure; objCmd.CommandTimeout = 7200; if (alParams.Count > 0) // 注意:这里应该用Count而不是Capacity,Capacity是容量不是实际元素数 { objCmd.Parameters.AddRange(AddDBParameter(ref alParams).ToArray()); } using (SqlDataAdapter objDataAdapter = new SqlDataAdapter(objCmd)) { objDataAdapter.Fill(SanitizeDataTable(dataSet)); GetDBParameterValuesSpecific(objCmd, ref alParams); } } } return dataSet; } catch (Exception ex) { throw ex; } // 不需要finally块,using会自动释放连接和命令对象
注意:原代码里用
alParams.Capacity > 0判断是否有参数是错误的,Capacity是集合的容量,不是实际元素数量,应该改成alParams.Count > 0。
4. 替换ArrayList为强类型集合
ArrayList是非泛型集合,类型不安全,建议改用List<SqlParameter>或者自定义的参数实体类,减少参数处理中的潜在问题。
内容的提问来源于stack exchange,提问作者Jatin D
相关产品推荐
相关产品推荐

