Java 任意文件下载漏洞

我们在开发 Web 应用时,经常会提供文件下载功能。对外暴露类似如下的URL

http://demo.com/download?fileName=foo.txt

这样的确很方便,但是,大家有没有想过,这样的功能可能会出现什么样的安全隐患或者漏洞呢?

下面是一段提供文件下载的spring mvc的java代码,使用fileName来指定要下载的文件。

    @GetMapping("/download")
    public ResponseEntity<Resource> download(@RequestParam("fileName") String fileName)
            throws IOException {

        Path filePath = Paths.get(PATH_PREFIX).toAbsolutePath().normalize()
                .resolve(fileName).normalize();
        Resource resource = new UrlResource(filePath.toUri());
        if (!resource.exists()) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType("application/octet-stream"))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + resource.getFilename())
                .body(resource);
    }

这里定了一个 PATH_PREFIX 常量,意图把访问限制在 PATH_PREFIX下。当fileName=../path/to/file 就跳出了限制,可以任意下载服务器上的问题,这是很严重的问题。

如果你的 DB 和业务代码配置在同一个服务器就可能被人脱库。

那么怎么解决这个问题呢?方案也有很多,例如:把文件路径存储到DB,客户端通过 fileId 下载文件。这里咱们讨论另一种简单的方案:

    @GetMapping("/download")
    public ResponseEntity<Resource> download(@RequestParam("fileName") String fileName)
            throws IOException {

        Path filePath = Paths.get(PATH_PREFIX).toAbsolutePath().normalize()
                .resolve(fileName).normalize();

        final String parentPathString = filePath.getParent().toAbsolutePath().toString();
        if (!parentPathString.startsWith(PATH_PREFIX)) {
            logger.error("illegal access!");
            return ResponseEntity.notFound().build();
        }

        Resource resource = new UrlResource(filePath.toUri());
        if (!resource.exists()) {
            return ResponseEntity.notFound().build();
        }
        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType("application/octet-stream"))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + resource.getFilename())
                .body(resource);
    }

上面红色标记部分,判断需要下载的文件的路径是否包含了PATH_PREFIX,包含则合法。注意前面经过了 normalize 处理。

posted @ 2022-11-28 17:56  景岳  阅读(531)  评论(0编辑  收藏  举报