C#使用Response.AddHeader下载Excel时如何防范Content-Disposition相关XSS漏洞
C# Excel下载场景防范Content-Disposition关联XSS攻击的方案
漏洞触发原因
现有代码直接将
myfile.Name字符串拼接进Content-Disposition响应头,如果文件名属于用户可控参数(比如用户自定义导出文件名、用户上传后再下载的文件名称),攻击者可以构造包含换行符、双引号、恶意脚本片段的特殊文件名,篡改响应头结构,触发响应头注入,最终导致存储型XSS漏洞。
修复方案
1. 使用官方内置类/方法处理文件名编码,禁止手动拼接未转义的文件名
根据你使用的.NET版本选择对应实现:
- .NET Core / .NET 5+ 版本:使用
ContentDispositionHeaderValue类自动处理编码转义,无需手动拼接
var contentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = myfile.Name, // 适配多浏览器的非ASCII字符显示 FileNameStar = myfile.Name }; Response.Headers[System.Net.HttpKnownHeaderNames.ContentDisposition] = contentDisposition.ToString(); // 后续代码保持不变 Response.AddHeader("Content-Length", myfile.Length.ToString()); Response.ContentType = "application/octet-stream"; Response.TransmitFile(myfile.FullName);
- .NET Framework 版本:使用
HttpUtility.UrlEncode对文件名做UTF8编码后再拼接
string encodedFileName = HttpUtility.UrlEncode(myfile.Name, System.Text.Encoding.UTF8); // 替换+号编码为%20,避免部分浏览器显示文件名时把空格识别为+号 encodedFileName = encodedFileName.Replace("+", "%20"); Response.AddHeader("Content-Disposition", $"attachment; filename=\"{encodedFileName}\""); // 后续代码保持不变 Response.AddHeader("Content-Length", myfile.Length.ToString()); Response.ContentType = "application/octet-stream"; Response.TransmitFile(myfile.FullName);
2. 额外加固措施
- 对用户可控的文件名做格式白名单校验,仅允许包含中英文、数字、下划线、减号、点号,过滤所有控制字符、换行符以及
\ / : * ? " < > |等非法文件名字符 - 若业务允许,优先使用服务端生成的随机安全文件名,仅在需要保留用户原始文件名的场景才做上述编码处理
- 保持ASP.NET默认的响应头安全校验配置,不要手动关闭响应头拆分拦截功能
内容的提问来源于stack exchange,提问作者newbies
相关产品推荐
相关产品推荐

