Spring Controller从文件系统限制下载文件

时间:2016-01-31 11:50:39

标签: java spring security servlets

我有一个带有/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或其他危险路径)

1 个答案:

答案 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)将为您做到这一点。