在文件上传中,代码扫描会产生 路径篡改(Path Manipulation)的缺陷,今天总结一下该问题的产生原因及解决方法。
一.问题描述
在使用 Fortify 扫描项目时,产生如下缺陷,该问题是说 使用如下代码:
request.getParameter(“bizId”) 直接作为上传文件名称组成字段时会产生 路径篡改
FileRelation relation = fileRelationService.upload(uploads, request.getParameter("bizId"),);
...
String attachmentFolder = this.getAttachmentFolderPath(xx, bizId , relationId);
File folder = new File(attachmentFolder);
二.产生原因
满足以下两个条件时会发生路径操作错误:
1. 攻击者能够指定文件系统上的操作中使用的路径。
2. 通过指定资源,攻击者获得了不允许的功能。
例如,程序可能使攻击者能够覆盖指定的文件或使用受攻击者控制的配置运行。
示例1:以下代码使用来自HTTP请求的输入来创建文件名。程序员没有考虑攻击者可能提供文件名,例如“…/…/tomcat/conf/server.xml”,这会导致应用程序删除其自己的配置文件之一。
String rName = request.getParameter("reportName");
File rFile = new File("/usr/local/apfr/reports/" + rName);
...
rFile.delete();
示例2:以下代码使用配置文件中的输入来确定要打开哪个文件并回显给用户。如果程序以足够的权限运行并且恶意用户可以更改配置文件,则他们可以使用该程序读取系统上以扩展名.txt结尾的任何文件。
fis = new FileInputStream(cfg.getProperty("sub")+".txt");
amt = fis.read(arr); out.println(arr);
三.解决办法
路径篡改最有效的解决办法就是避免用户直接输入文件名,建立文件白名单的形式。但我们在涉及文件上传时,往往无法限定一个白名单。退而求其次,我们无法控制用户或黑客对文件名的输入,但我们可以使用过滤特殊字符的方式,对输入的内容进行校验。
在这里我们自定义一个特殊字符的 过滤类 CleanPathUtil ,
在从前端接收的文件名相关参数进行特殊字符过滤:
bizId = CleanPathUtil.cleanString(request.getParameter("bizId"));
FileRelation relation = fileRelationService.upload(uploads, bizId, sysUser);
/**
* 过滤字符串帮助类
*/
public class CleanPathUtil {
public static String cleanString(String aString) {
if (aString == null) return null;
String cleanString = "";
for (int i = 0; i < aString.length(); ++i) {
cleanString += cleanChar(aString.charAt(i));
}
return cleanString;
}
private static char cleanChar(char aChar) {
// 0 - 9
for (int i = 48; i < 58; ++i) {
if (aChar == i) return (char) i;
}
// 'A' - 'Z'
for (int i = 65; i < 91; ++i) {
if (aChar == i) return (char) i;
}
// 'a' - 'z'
for (int i = 97; i < 123; ++i) {
if (aChar == i) return (char) i;
}
// other valid characters
switch (aChar) {
case '/':
return '/';
case '.':
return '.';
case '-':
return '-';
case '_':
return '_';
case ' ':
return ' ';
}
return '%';
}
}