为解决任意文件上传漏洞,添加白名单校验文件后缀名
1)添加配置信息
file_strict_name=true
file_special_characters=
file_allow_types=jpg,png,tif,gif,dwg,pdf,zip,docx,doc,xls,xlsx
file_allows=true
2)添加白名单校验方法
@Service
public class ObsService {
/**
* 是否要判断文件名含有非法字符
*/
@Value("${file_strict_name}")
private String fileStrictName;
/**
* 文件名含有的特殊字符
*/
@Value("${file_special_characters}")
private String fileSpecialCharacters;
/**
* 允许上传的文件类型
*/
@Value("${file_allow_types}")
private String[] fileAllowTypes;
/**
* 是否开启文件类型白名单
*/
@Value("${file_allows}")
private String fileAllows;
/**
* 判断文件名中是否含有非法字符
* @param fileName
*/
public void illegalCharacters(String fileName) throws Exception{
if(StringUtils.isNotBlank(fileStrictName) && Boolean.valueOf(fileStrictName)) {
//要判断文件名中是否包含非法字符
if(StringUtils.isNotBlank(fileName)) {
//默认允许包含中文、英文、数字包括下划线
String n = "[\\u4E00-\\u9FA5A-Za-z0-9_]+";
//不为空则拼接上
if (null != fileSpecialCharacters && !"".equals(fileSpecialCharacters)) {
n = "[\\u4E00-\\u9FA5A-Za-z0-9_" + fileSpecialCharacters+"]+";
}
Pattern pattern = Pattern.compile(n);
String nn = fileName;
int last = nn.lastIndexOf(".");
if (last != -1) {
//截取掉扩展名好判断一些
nn = nn.substring(0,last);
}
Matcher mat = pattern.matcher(nn);
if(!mat.matches()){
throw new RuntimeException("文件名包含非法的字符,文件名允许输入【汉字,汉字标点符号,字母,数字,下划线,空格】");
}
}
}
}
/**
* 上传文件类型是否在白名单中
* @param fileName
*/
public void whiteListVerify(String fileName) throws Exception{
if(StringUtils.isNotBlank(fileAllows) && Boolean.valueOf(fileAllows)) {
if(StringUtils.isNotBlank(fileName)) {
String nn = fileName;
int last = nn.lastIndexOf(".");
if (last != -1) {
//截取掉扩展名好判断一些
nn = nn.substring(last+1, nn.length());
}
if(fileAllowTypes != null) {
List<String> fileAllowsList = Arrays.asList(fileAllowTypes);
if(!fileAllowsList.contains(nn.toLowerCase())) {
throw new RuntimeException("文件【"+fileName+"】格式不正确,请上传["+StringUtils.join(fileAllowTypes, ",")+"]格式的文件");
}
}
}
}
}
}
3)在文件上传接口中,调用白名单校验接口
@PostMapping("putFile")
@Transactional
public void putObject(HttpServletRequest request) throws Exception {
List<MultipartFile> files = ((MultipartHttpServletRequest)request).getFiles("name");
String businessType = request.getParameter("businessType");
String businessMid = request.getParameter("businessKey");
Attachments attachments = null;
for(MultipartFile file: files) {
try {
//设置文件业务信息
String fileName = file.getOriginalFilename();
try {
//判断文件名中是否含有非法字符
obsService.illegalCharacters(fileName);
//文件类型是否包含在白名单中
obsService.whiteListVerify(fileName);
}catch (Exception e1) {
// TODO: handle exception
throw e1;
}
......
} catch (Exception e) {
log.error("文件上传失败", e);
throw e;
}
}
}