java解决PDF中的XSS攻击

1、依赖

<dependency>
      <groupId>org.apache.pdfbox</groupId>
      <artifactId>pdfbox</artifactId>
      <version>2.0.26</version>
</dependency>

2、

public String uploadFile(MultipartFile file) throws Exception
    {
        Boolean result;
        final ExecutorService exec = Executors.newFixedThreadPool(1);
        Callable<Boolean> isXss = () -> {
            //开始执行耗时操作,需要加上pdf后缀,否则也可以通过抓包修改ContentType来绕过检查
            if ((("pdf".equalsIgnoreCase(FileTypeUtils.getFileType(file.getOriginalFilename()))) ||
                    MediaType.APPLICATION_PDF_VALUE.equals(file.getContentType())) &&
                    FileUtils.containsJavaScript(FileUtils.multipartFileToFile(file))) {
                return true;
            } else {
                return false;
            }
        };
        try {
            Future<Boolean> future = exec.submit(isXss);
            //这一步是为了防止那些比较大的PDF导致系统挂死的问题,如果超过3s则默认认为文件安全::>_<::
            result = future.get(1000 * 3, TimeUnit.MILLISECONDS); //任务处理超时时间设为 3 秒
            log.info("result:{}",result);
        } catch (TimeoutException ex) {
            log.info("调用接口,处理3s超时......");
            result = false;
            ex.printStackTrace();
        } catch (Exception e) {
            log.info("调用接口,处理失败......");
            result = false;
            e.printStackTrace();
        }
        // 关闭线程池
        exec.shutdown();
        if(result){
            throw new CustomException("所上传文件可能具有XSS攻击,请重新上传安全文件!");
        }
        String name = FileUploadUtils.upload(localFilePath, file);
        return name;
    }

   /**
     * File转MultipartFile
     * @param file 文件对象
     * @return Multipart文件对象
     */
    public static File multipartFileToFile(MultipartFile mulFile) throws IOException {
        InputStream ins = mulFile.getInputStream();
        String fileName = mulFile.getOriginalFilename();
        String prefix = getFileNameNoSuffix(fileName) + UUID.randomUUID().toString();
        String suffix = "." + getSuffixNameName(fileName);
        File toFile = File.createTempFile(prefix, suffix);
        OutputStream os = new FileOutputStream(toFile);
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        ins.close();
        return toFile;
    }

   /**
     * 获取不带扩展名的文件名
     */
    public static String getFileNameNoSuffix(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length()))) {
                return filename.substring(0, dot);
            }
        }
        return filename;
    }

    /**
     * 获取文件扩展名
     */
    public static String getSuffixNameName(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length() - 1))) {
                return filename.substring(dot + 1);
            }
        }
        return filename;
    }

    /**
     * 校验pdf文件是否包含js脚本
     **/
    public static boolean containsJavaScript(File file) throws IOException {
        RandomAccessFile is = new RandomAccessFile(file, "r");
        try{
            PDFParser parser = new PDFParser(is);
            parser.parse();
            PDDocument doc = parser.getPDDocument();
            String CosName = doc.getDocument().getTrailer().toString();
            if(CosName.contains("COSName{JS}")){
                return true;
            }
        }catch (Exception e){
            System.out.println("PDF效验异常:"+e.getMessage());
        }finally {
            is.close();
        }
        return false;
    }
    /**
     * File转MultipartFile
     * @param file 文件对象
     * @return Multipart文件对象
     */
    public static MultipartFile getMultipartFile(File file) {
        FileItem item = new DiskFileItemFactory().createItem("file"
                , MediaType.MULTIPART_FORM_DATA_VALUE
                , true
                , file.getName());
        try (InputStream input = new FileInputStream(file);
             OutputStream os = item.getOutputStream()) {
            // 流转移
            IOUtils.copy(input, os);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid file: " + e, e);
        }

        return new CommonsMultipartFile(item);
    }
posted @ 2024-02-05 15:09  蓝色土耳其  阅读(1020)  评论(0编辑  收藏  举报