AppScan报CWE-116 Validation.EncodingRequired漏洞修复咨询
CWE-116(Validation.EncodingRequired)告警修复方案
CWE-116的核心风险是未对用户可控的输出内容做正确的编码、校验或转义,AppScan标记outputStream.write(formFile.getFileData())的原因是代码直接将用户上传的未做任何校验的原始文件内容写入服务器磁盘,同时代码还存在路径遍历、前端XSS等关联风险,需同步修复:
具体修复步骤
- 第一步:校验并标准化文件名,防范路径遍历攻击
不要直接用formFile.getFileName()拼接存储路径,攻击者可构造包含../的恶意文件名穿越目录写入任意路径,同时部分浏览器会传递完整本地路径,需先提取纯文件名再加白名单校验:String fileName = formFile.getFileName(); if (fileName == null || fileName.trim().isEmpty()) { throw new IllegalArgumentException("文件名为空"); } // 去除路径前缀,只保留纯文件名 fileName = new File(fileName).getName(); // 业务侧配置允许的文件后缀白名单 String[] allowedSuffix = {"jpg", "png", "pdf", "doc"}; int dotIndex = fileName.lastIndexOf("."); if (dotIndex < 0) { throw new IllegalArgumentException("文件无合法后缀"); } String suffix = fileName.substring(dotIndex + 1).toLowerCase(); if (!Arrays.asList(allowedSuffix).contains(suffix)) { throw new IllegalArgumentException("不允许上传该类型文件"); } - 第二步:校验文件内容,通过后再写入磁盘
直接写入原始字节流存在上传恶意脚本、病毒文件的风险,需先校验文件大小、文件魔数,确认文件内容与后缀匹配:byte[] fileData = formFile.getFileData(); // 校验文件大小上限,按需调整阈值,这里示例为10M if (fileData.length > 10 * 1024 * 1024) { throw new IllegalArgumentException("文件大小超出限制"); } // 校验文件魔数,和后缀匹配,避免文件内容伪造 boolean validFile = false; if ("jpg".equals(suffix)) { // jpg文件魔数头为FFD8FF validFile = (fileData[0] & 0xFF) == 0xFF && (fileData[1] & 0xFF) == 0xD8 && (fileData[2] & 0xFF) == 0xFF; } else if ("png".equals(suffix)) { // png文件魔数头为89504E47 validFile = (fileData[0] & 0xFF) == 0x89 && (fileData[1] & 0xFF) == 0x50 && (fileData[2] & 0xFF) == 0x4E; } // 其他允许的后缀类型魔数校验自行补充 if (!validFile) { throw new IllegalArgumentException("文件内容与后缀不匹配,禁止上传"); } // 校验通过后再写入磁盘 outputStream.write(fileData); - 第三步:修复前端输出的编码问题,避免XSS风险
直接将原始文件名拼接到返回给前端的提示信息中,攻击者可构造带脚本标签的恶意文件名触发XSS,属于CWE-116覆盖的风险场景,需对文件名做HTML转义后再使用:// 对文件名做HTML转义后再拼接提示信息 String safeFileName = org.apache.commons.lang.StringEscapeUtils.escapeHtml(fileName); uploadForm.setMessage("The file "+safeFileName+" is uploaded successfully."); - 可选优化:使用随机文件名存储
可生成随机文件名代替用户上传的原始文件名存储到服务器,彻底规避路径遍历、文件名注入的风险:// 生成随机文件名,保留原后缀 String saveFileName = UUID.randomUUID().toString().replace("-", "") + "." + suffix; String path = getServlet().getServletContext().getRealPath("") + "/" + saveFileName;
内容的提问来源于stack exchange,提问作者Second One
相关产品推荐
相关产品推荐

