如何修复Checkmarx报告中的“Reflected XSS All Clients”问题?
修复Checkmarx检测出的"Reflected XSS All Clients"高风险问题
问题背景
代码被Checkmarx检测出151个高风险的“Reflected XSS All Clients”问题,所有问题模式一致:以dtIn为源对象,最终流向SerializeObject输出。
代码示例(/DEBT/DEBT/Controllers/DEBT440Controller.cs):
176. public string GetHistory(DataTableIn dtIn) .... 184. model = JsonConvert.DeserializeObject<DEBTM440Model>(dtIn.findJson); .... 189. var data = _service.Use(t => t.GetHistory(model));
Checkmarx报告指出:_service.Use方法在DEBT047Controller.cs第175行通过GetPage将不可信数据嵌入输出,未经过滤编码,攻击者可篡改dtIn输入发起反射型跨站脚本(XSS)攻击。
尝试修改DataTableIn类,添加SanitizeAndEncode和EncodeJsonValue方法进行HTML编码处理,同时在控制器反序列化前调用该方法,但方案完全无效,需有效修复方法。
已尝试的无效代码
DataTableIn类修改代码:
using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Web; namespace ABT.Entity { public class DataTableIn { public int draw { get; set; } public int start { get; set; } public int length { get; set; } public int recordsFiltered { get; set; } public string findJson { get; set; } public DataTableSearchIn search { get; set; } public List<DataTableOrderIn> order { get; set; } public DataTableIn SanitizeAndEncode() { DataTableIn sanitizedData = new DataTableIn(); // Sanitize and encode "findJson" JObject jsonObject = JObject.Parse(findJson); // Iterate through the fields in the JSON object foreach (var field in jsonObject) { // Encode the field's value string fieldName = field.Key; string fieldValue = field.Value.ToString(); string encodedFieldValue = EncodeJsonValue(fieldValue); jsonObject[fieldName] = encodedFieldValue; } findJson = jsonObject.ToString(); // Sanitize and encode search terms if (search != null) { search.value = HttpUtility.HtmlEncode(search.value); } if (order != null) { foreach (DataTableOrderIn order in order) { order.column = Math.Min(order.column, 0); } } sanitizedData.findJson = findJson; sanitizedData.search = search; sanitizedData.order = order; sanitizedData.draw = Math.Max(draw, 0); sanitizedData.start = Math.Max(start, 0); sanitizedData.length = Math.Max(length, 0); sanitizedData.recordsFiltered = Math.Max(recordsFiltered, 0); return sanitizedData; } public string EncodeJsonValue(string value) { // Encode special characters in the value string encodedValue = value .Replace("\\", "\\\\") // Escape backslashes .Replace("\"", "\\\"") // Escape double quotes .Replace("\n", "\\n") // Escape newlines .Replace("\r", "\\r") // Escape carriage returns .Replace("\t", "\\t"); // Escape tabs // Apply HTML encoding to the encoded value string htmlEncodedValue = HttpUtility.HtmlEncode(encodedValue); return htmlEncodedValue; } } public class DataTableOrderIn { public int column { get; set; } public EnumOrderType dir { get; set; } } public class DataTableSearchIn { //search value public string value { get; set; } public bool regex { get; set; } } public enum EnumOrderType { Asc, Desc } }
控制器修改代码:
.... 189. public string GetHistory(DataTableIn dtIn) .... 209. dtIn = dtIn.SanitizeAndEncode(); .... 214. model = JsonConvert.DeserializeObject<DEBTM575Model>(dtIn.findJson);
有效修复方案
1. 调整编码时机:输出阶段编码而非输入阶段
之前的核心错误是在输入反序列化前做HTML编码,导致业务逻辑处理的是编码后的数据,既可能破坏业务数据准确性,还可能引发双重编码问题。正确逻辑是:
- 输入阶段仅做数据验证(校验字段类型、长度、合法范围),保留原始可信数据
- 在最终序列化输出到客户端的阶段,对所有包含用户输入的字段做对应场景的编码
2. 针对DataTables场景的输出编码实现
假设服务最终将数据序列化为JSON返回给前端,需确保所有来自用户输入的字段在序列化前完成HTML编码:
var data = _service.Use(t => t.GetHistory(model)); // 遍历结果集,对所有用户输入来源的字段编码 foreach (var item in data.Items) { item.UserInputField1 = HttpUtility.HtmlEncode(item.UserInputField1); item.UserInputField2 = HttpUtility.HtmlEncode(item.UserInputField2); // 其他涉及用户输入的字段同理 } // 序列化输出 return JsonConvert.SerializeObject(data);
3. 利用序列化工具的安全配置自动编码
使用Newtonsoft.Json时,可配置全局自动HTML编码字符串字段,避免手动编码遗漏:
var jsonSettings = new JsonSerializerSettings { StringEscapeHandling = StringEscapeHandling.EscapeHtml }; return JsonConvert.SerializeObject(data, jsonSettings);
4. 增强输入验证(非编码,仅做安全校验)
输入阶段需严格校验数据合法性,过滤危险内容:
if (dtIn.search != null && !string.IsNullOrEmpty(dtIn.search.value)) { // 过滤HTML标签 dtIn.search.value = Regex.Replace(dtIn.search.value, @"<[^>]+>", string.Empty); // 限制输入长度 if (dtIn.search.value.Length > 200) dtIn.search.value = dtIn.search.value.Substring(0, 200); } // 校验findJson中的字段类型,比如数字字段必须为数字 JObject findObj = JObject.Parse(dtIn.findJson); foreach (var prop in findObj.Properties()) { if (prop.Value.Type == JTokenType.String && prop.Name.Contains("Id")) { if (!int.TryParse(prop.Value.ToString(), out _)) throw new ArgumentException("非法的ID格式"); } }
内容的提问来源于stack exchange,提问作者Wei Chung Shih
相关产品推荐
相关产品推荐

