# [Security] Second-Order SSRF in jeecgboot_JeecgBoot #9553 ## 漏洞概述 在 `jeecgboot_JeecgBoot` 的公告文件下载功能中存在一个二阶服务器端请求伪造(SSRF)漏洞。攻击者可以通过 `POST /sys/announcement/add` 接口注入恶意的 HTTP URL 到公告的 `files` 字段中。当用户或管理员随后通过 `GET /sys/announcement/downloadFiles` 触发公告附件下载时,服务器会使用 `HttpURLConnection` 获取注入的 URL,且没有 SSRF 防护。这使得攻击者能够扫描内网、访问本地服务并检索敏感数据(如云元数据)。 ## 影响范围 - **受影响版本**:<=v3.9.1 - **受影响组件**: - `SysAnnouncementController.java` (L139-161, L751-756) - `SysAnnouncementServiceImpl.java` (L271-326) - `FileDownloadUtils.java` (L259-279) - **受影响函数/方法**: - `SysAnnouncementController.add()` - `SysAnnouncementServiceImpl.downloadFiles()` - `FileDownloadUtils.getDownInputStream()` - **入口点**: - POST `/sys/announcement/add` (注入) - GET `/sys/announcement/downloadFiles` (执行) ## 修复方案 1. **输入验证**:在 `SysAnnouncementController.add()` 方法中,对 `files` 参数进行严格的 URL 格式和协议验证,禁止注入非预期的 URL。 2. **SSRF 防护**:在 `FileDownloadUtils.getDownInputStream()` 方法中,增加对 HTTP 请求的 SSRF 防护,例如限制请求的目标地址为白名单内的地址,或者禁止请求内网地址。 3. **代码示例**: ```java // 在 FileDownloadUtils.java 中 public static InputStream getDownInputStream(String fileId, String uploadUrl) { try { // HTTP URL: NO SSRF PROTECTION if (StringUtils.isNotEmpty(uploadUrl) && uploadUrl.startsWith(CommonConstant.STR_HTTP)) { URL url = new URL(uploadUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(5000); connection.setReadTimeout(30000); return connection.getInputStream(); // SSRF HERE } else { // Local file: Protected by SsrfilePathFilter String downloadFilePath = uploadUrl + File.separator + fileId; SsrfilePathFilter.checkPathTraversal(downloadFilePath); return new BufferedInputStream(new FileInputStream(downloadFilePath)); } } catch (IOException e) { return null; } } ``` ## POC 代码 ```json { "title": "Important Announcement", "remarkContent": "Please review attachments", "files": "http://109.254.169.254/latest/meta-data/iam/security-credentials/http://192.168.1.1/admin" } ```