{"record":{"id":"69143f2b756eb807","repo":"jeecgboot/JeecgBoot","slug":"storepath-69143f","errorCode":null,"errorMessage":"存储路径校验失败: {storePath}","messagePattern":"存储路径校验失败: (.+?)","errorType":"exception","errorClass":"JeecgBootException","httpStatus":null,"severity":"error","filePath":"jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/FileDownloadUtils.java","lineNumber":144,"sourceCode":"     * 下载网络资源到磁盘\n     *\n     * @param fileUrl\n     * @param storePath\n     * @author chenrui\n     * @date 2024/1/19 10:09\n     */\n    public static String download2DiskFromNet(String fileUrl, String storePath) {\n        //update-begin---author:liusq ---date:2026-03-30  for：【issues/9437】修复download2DiskFromNet storePath路径遍历漏洞(CWE-22)-----------\n        // 路径遍历校验：拦截 ../ 等遍历字符，并确保规范化路径与原始路径一致\n        SsrfFileTypeFilter.checkPathTraversal(storePath);\n        try {\n            String canonicalPath = new File(storePath).getCanonicalPath();\n            String absolutePath = new File(storePath).getAbsolutePath();\n            if (!canonicalPath.equals(absolutePath)) {\n                throw new JeecgBootException(\"非法存储路径，路径包含遍历字符: \" + storePath);\n            }\n        } catch (IOException e) {\n            throw new JeecgBootException(\"存储路径校验失败: \" + storePath, e);\n        }\n        //update-end---author:liusq ---date:2026-03-30  for：【issues/9437】修复download2DiskFromNet storePath路径遍历漏洞(CWE-22)-----------\n        //update-begin---author:zhangdaihao ---date:2026-04-15  for：【issues/9553】下载网络资源前增加SSRF校验-----------\n        SsrfFileTypeFilter.checkSsrfHttpUrl(fileUrl);\n        //update-end---author:zhangdaihao ---date:2026-04-15  for：【issues/9553】下载网络资源前增加SSRF校验-----------\n        try {\n            URL url = new URL(fileUrl);\n            URLConnection conn = url.openConnection();\n            // 设置超时间为3秒\n            conn.setConnectTimeout(3 * 1000);\n            // 防止屏蔽程序\n            conn.setRequestProperty(\"User-Agent\", \"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)\");\n            // 确保目录存在\n            File file = ensureDestFileDir(storePath);\n            try (InputStream inStream = conn.getInputStream();\n                 FileOutputStream fs = new FileOutputStream(file);) {\n                int byteread;\n                byte[] buffer = new byte[1204];","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/jeecgboot/JeecgBoot/blob/96fb33f5ec68516da0b0147da06b2eb0419e063a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/FileDownloadUtils.java#L126-L162","documentation":"Thrown by FileDownloadUtils.download2DiskFromNet when File.getCanonicalPath() or getAbsolutePath() raises an IOException during the path-traversal check. The original IOException is wrapped as the cause of a JeecgBootException with the message '存储路径校验失败'. It indicates the filesystem could not resolve storePath, not that traversal was detected.","triggerScenarios":"Calling download2DiskFromNet with a storePath whose parent directory does not exist, contains illegal characters (Windows), points to an unreadable location, or triggers a filesystem-level I/O error during canonical-path resolution.","commonSituations":"Storage directory not yet created on a fresh deployment; permission denied on the configured upload path; storePath derived from a misconfigured property that points to a non-existent drive or mount; Windows path with reserved/illegal characters.","solutions":["Ensure the target storage directory exists and the application process has read/write permission on it before invoking download2DiskFromNet.","Call Files.createDirectories(Path.of(storePath).getParent()) prior to the download.","Verify the storePath configuration value in application yml resolves to a real, writable directory.","Catch JeecgBootException at the caller and surface a user-friendly message, logging the wrapped IOException cause."],"exampleFix":"// before\nFileDownloadUtils.download2DiskFromNet(fileUrl, storePath);\n\n// after\nPath parent = Path.of(storePath).toAbsolutePath().getParent();\nif (!Files.exists(parent)) {\n    Files.createDirectories(parent);\n}\nFileDownloadUtils.download2DiskFromNet(fileUrl, storePath);","handlingStrategy":"validation","validationCode":"Path store = Path.of(storePath);\nPath parent = store.toAbsolutePath().getParent();\nif (!Files.isDirectory(parent)) {\n    Files.createDirectories(parent);\n}\nif (!Files.isWritable(parent)) {\n    throw new IllegalStateException(\"存储目录不可写: \" + parent);\n}","typeGuard":"null","tryCatchPattern":"try {\n    FileDownloadUtils.download2DiskFromNet(fileUrl, storePath);\n} catch (JeecgBootException e) {\n    log.error(\"存储路径校验失败\", e);\n    return Result.error(\"存储路径不可用，请联系管理员\");\n}","preventionTips":["Ensure storage directories exist and are writable at application startup.","Use absolute, real (non-symlinked) paths for storage configuration.","Log the wrapped IOException cause to diagnose filesystem-level failures."],"tags":["security","path-traversal","io","file-download","filesystem"],"backgroundTag":null,"analyzedSha":"96fb33f5ec68516da0b0147da06b2eb0419e063a","analyzedAt":"2026-08-14T00:04:16.786Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}