我有一个带有/file
映射的Spring控制器,它从用户获取文件名,并将文件内容传输给用户
@RequestMapping(value = "/file" , method = RequestMethod.GET)
@ResponseBody
public void getFile(@RequestParam(value = "name", required = true) String fileName,
HttpServletResponse response)
{
String fileExtension = "";
int i = fileName.lastIndexOf('.');
if (i > 0) {
fileExtension = fileName.substring(i+1);
}
// file extension for requested file must be xls
if(!fileExtension.equals("xls"))
{
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
try {
Path path = Paths.get("/tmp/" + fileName);
byte[] data = Files.readAllBytes(path);
response.setHeader("Content-Disposition", "inline; filename=" + fileName);
response.setContentType("application/vnd.ms-excel");
response.setContentLength(data.length);
try {
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(data);
outputStream.flush();
} catch (Exception e) {
}
} catch (Exception e) {
}
}
用户只能在.xls
文件夹中下载tmp
扩展名的文件。此代码的问题是用户可以更改目录并下载其他目录中的其他.xls
文件。例如,如果此路径中有文件/tmp/tmp2/ab.xls
,则用户可以通过调用此URL http://myserver.mydomain:myport/mycontext/file?name=tmp2/ab.xls
来下载该文件,这是一个安全漏洞。检查我从用户提供的名称的最佳方法是文件名吗? (不是directory/filename
或../filename
或其他危险路径)
答案 0 :(得分:1)
Path tmpPath = Paths.get("/tmp/"); //valid directory
String fileName = "foo/bar.xls"; //supplied fileName
Path filePath = tmpPath.resolve(fileName); //add fileName to path
Path fileParent = filePath.getParent(); //get parent directory
System.out.println(fileParent);
System.out.println(tmpPath.equals(fileParent)); //false because fileParent is '/tmp/foo'
' tmpPath'将等于' fileParent'如果您提供有效的fileName,例如' bar.xls'。
我认为您还可以简化扩展程序检查:filePath.endsWith(".xls");
应该足够了。并且不要连接文件路径(" / tmp /" + fileName)。 Paths.get(" / tmp",fileName)将为您做到这一点。