Java代码审计实战:SSRF漏洞原理、挖掘与纵深防御体系构建

发布时间:2026/7/1 17:17:51
Java代码审计实战:SSRF漏洞原理、挖掘与纵深防御体系构建 1. 项目概述为什么SSRF是Java安全审计的重中之重如果你是一名Java开发者或者正在向安全研究、代码审计方向转型那么“SSRF”这个词你一定不陌生。它不像SQL注入那样“历史悠久”也不像XSS那样“耳熟能详”但在现代微服务、云原生架构下SSRFServer-Side Request Forgery服务端请求伪造的杀伤力与日俱增已经成为渗透测试和代码审计中必须攻克的堡垒。简单来说SSRF就是攻击者能够诱骗服务器代替攻击者去发起一个网络请求。这个请求的目标往往是服务器自身内网、云上元数据服务或者其他外部系统。听起来似乎只是“代发个请求”但它的危害链条可以非常长从读取服务器本地文件、扫描内网端口到攻击Redis、MySQL等内网脆弱服务甚至通过云元数据接口窃取AK/SK访问密钥导致整个云环境沦陷。我见过太多因为一个不起眼的URL参数校验不严导致整个内网被“打穿”的案例。尤其是在Java生态中大量的HTTP客户端库如HttpURLConnection、Apache HttpClient、OkHttp、RestTemplate等、XML解析库以及各类第三方SDK如果使用不当都可能成为SSRF漏洞的入口点。因此掌握Java代码中的SSRF审计不仅仅是为了找出漏洞更是为了深入理解Java网络编程的安全边界建立起一道稳固的服务器端防线。这篇文章我将带你从零基础开始彻底搞懂SSRF的原理、在Java代码中的常见“案发现场”、完整的攻击利用流程以及如何从防御角度进行代码审计。无论你是想提升代码安全性的开发者还是立志成为白帽子的安全新人收藏这一篇足够你构建起系统的SSRF知识体系。2. SSRF漏洞核心原理与Java语境下的特殊性要审计漏洞必须先理解漏洞产生的根源。SSRF的本质是**“信任边界”的混淆**。服务器代码错误地将用户可控的输入当成了可信的、用于发起后端请求的目标地址。2.1 漏洞产生的核心逻辑想象一个场景你服务器有一个跑腿小弟HTTP客户端。正常情况下你只会让小弟去你信得过的几家店铺可信的内网或白名单外网服务取东西。但有一天一个陌生人攻击者递给你一张纸条上面写着一个地址。你没有核实这个地址是否安全就直接把纸条给了跑腿小弟。小弟忠实地按照地址去了结果这个地址可能是你家后院file:///etc/passwd小弟把你家的秘密文件拿回来了。小区里其他邻居家不锁门的仓库内网192.168.1.10:6379小弟进去把邻居的Redis数据库给清空了。一个伪装成快递站的强盗窝点恶意网站小弟一去就被扣下或者被诱导去干坏事如发起二次攻击。在代码层面这个过程抽象为// 漏洞代码示例 String url request.getParameter(url); // 攻击者可控的输入 HttpClient client HttpClient.newHttpClient(); HttpRequest req HttpRequest.newBuilder() .uri(URI.create(url)) // 危险未经验证的URI直接用于构建请求 .build(); HttpResponseString response client.send(req, HttpResponse.BodyHandlers.ofString());上述代码中url参数完全由用户控制并直接用于构造HTTP请求这就是最经典的SSRF漏洞模式。2.2 Java中SSRF的特殊性与常见风险点Java的丰富生态和强大网络库在带来便利的同时也引入了特定的风险点协议处理器的多样性Java的URI/URL类支持多种协议httphttpsfileftpgopherjarnetdoc等。攻击者可以利用file://协议读取服务器本地文件或者利用一些旧版本JDK中支持的gopher协议进行更复杂的攻击。URL解析的歧义Java的URL解析可能产生非预期行为。例如利用符号进行身份认证混淆http://expected-hostattacker-host或者利用#片段标识、DNS重绑定等技术绕过基于字符串的过滤。重定向的滥用许多HTTP客户端如默认跟随重定向的HttpURLConnection会自动处理3xx重定向。攻击者可以提供一个指向恶意地址的重定向链接客户端校验了第一个URL却请求了重定向后的危险URL。第三方库的默认行为像Apache HttpClient、OkHttp、Spring的RestTemplate等它们功能强大但默认配置可能不安全。例如某些库可能默认不校验SSL证书或对重定向、超时的处理不够严格可能被利用。与上下游漏洞的链式反应SSRF很少单独造成毁灭性打击但它是一个绝佳的“跳板”。它常与以下漏洞结合XXEXML外部实体注入如果应用解析用户上传的XML且实体解析未禁用攻击者可通过XXE触发SSRF让服务器从内部系统读取数据。反序列化漏洞某些反序列化载荷中可以包含URL连接操作从而触发SSRF。云元数据服务攻击在AWS、阿里云、腾讯云等环境中内网有一个特殊的端点如http://169.254.169.254/用于查询实例的元数据包括临时访问凭证。SSRF漏洞可以直接访问这个端点获取云服务器的AK/SK后果极其严重。实操心得审计Java SSRF时脑子里要有一张“地图”。这张地图包括用户输入入口点参数、Header、Body、请求发起层用了哪个客户端库、目标地址解析过程URL如何处理、网络访问结果的处理响应如何返回给用户。沿着这条数据流逐一检查每个环节的校验和过滤是否到位。3. Java代码审计中SSRF的常见漏洞模式挖掘知道了原理我们就要在代码中寻找这些“信任混淆”的点。以下是我在大量审计实践中总结出的高频漏洞模式。3.1 模式一直接拼接用户输入构造请求这是最原始、也最常见的模式。审计时搜索关键词new URI()new URL()StringBuilder.append(url)HttpClient.createRestTemplate.getForObject等。漏洞代码示例GetMapping(/fetch) public String fetchImage(RequestParam String imageUrl) { // 场景提供一个URL服务器下载图片并处理 RestTemplate restTemplate new RestTemplate(); // 直接使用用户输入的imageUrl无任何过滤 byte[] imageData restTemplate.getForObject(imageUrl, byte[].class); return processImage(imageData); }攻击PayloadimageUrlhttp://169.254.169.254/latest/meta-data/iam/security-credentials/攻击AWS元数据3.2 模式二解析XML、Office文档等富媒体内容许多文件格式内部可以包含外部资源引用。解析器在处理这些引用时可能会自动发起网络请求。漏洞代码示例XXE触发SSRFDocumentBuilderFactory dbf DocumentBuilderFactory.newInstance(); DocumentBuilder db dbf.newDocumentBuilder(); // 从用户上传的XML文件解析 Document doc db.parse(new File(uploadedXmlFile)); // 如果XML中包含 !ENTITY xxe SYSTEM http://internal-service/secret解析过程就会发起请求。审计要点检查所有XML解析器DOM SAX StAX是否设置了XMLConstants.FEATURE_SECURE_PROCESSING是否禁用了DTD和外部实体。同样对于PDF、Excel、Word文档解析要关注相关库如Apache POI是否有关闭外部资源加载的配置。3.3 模式三数据库连接、缓存客户端等配置参数注入有时SSRF的入口不那么直接。例如应用从数据库读取一个“配置中心”的地址而这个地址最初是用户可控的。漏洞代码示例// 从数据库读取一个外部API网关地址 String apiGateway configService.getConfig(external_api_gateway); // 假设攻击者通过其他漏洞如SQL注入、配置管理后台将该值修改为内网地址 RestTemplate template new RestTemplate(); String result template.getForObject(apiGateway /getData, String.class);审计要点关注所有从“动态配置源”数据库、配置中心、环境变量获取并用于发起网络请求的字符串。确保这些配置源本身有严格的权限控制且取值在使用前经过了校验。3.4 模式四URL白名单校验的常见绕过手法很多开发者知道要校验URL但实现的校验逻辑存在缺陷。以下是几种经典的绕过方式利用符号http://expected-hostattacker-host。一些简单的正则匹配^http://www.trusted.com/可能会通过但实际请求会发往attacker-host。利用IP地址的多种表示形式十进制IPhttp://2130706433等价于http://127.0.0.1八进制IPhttp://0177.0.0.1等价于http://127.0.0.1十六进制IPhttp://0x7f.0x0.0x0.0x1等价于http://127.0.0.1IPv6地址http://[::1]或http://[0:0:0:0:0:0:0:1]等价于http://127.0.0.1利用DNS重绑定攻击者控制一个域名其DNS记录的TTL极短。第一次解析时返回一个合法的、在白名单内的IP地址通过校验。但在Java客户端实际发起请求的瞬间DNS记录已变更为攻击目标的内网IP。这种攻击对基于“解析前”的字符串校验是致命的。利用不完整的URL或畸形URLhttp://127.0.0.1:80evil.comhttp://127.0.0.1\\evil.com 或者利用#片段使校验逻辑失效。注意事项绝对不要使用正则表达式作为SSRF防御的主要手段。正则表达式极难写全、极难维护且极易被绕过。防御的核心应该是“解析后校验”和“默认拒绝”。4. 从零构建SSRF漏洞攻击流程实战视角理解了漏洞点我们模拟攻击者的视角来看一个完整的SSRF攻击流程是如何展开的。这能帮助我们在审计时更好地评估漏洞的危害等级。4.1 第一步信息收集与入口点探测攻击不会凭空开始。攻击者首先会进行信息收集功能点分析寻找任何涉及“URL调用”、“图片/文件下载”、“内容获取”、“网页预览”、“转码服务”、“请求代理”等功能。这些功能点很可能将用户输入的URL作为参数。参数爆破使用工具如Burp Suite的Intruder对已知参数进行FUZZ尝试urllinksrcpathfileapi等参数名并提交各种Payload观察响应。代码/错误信息泄露有时错误信息会暴露后端使用的技术栈如Java Spring甚至部分代码逻辑这能给攻击者提供线索。4.2 第二步漏洞验证与初步利用发现可疑参数后需要验证其是否存在SSRF并判断可利用程度。基础验证提交一个指向公网可控服务器的URL如Burp Collaborator或RequestBin地址观察服务器是否发起了请求以及请求中携带了哪些信息如IP、User-Agent、Header。协议探测尝试不同协议探测服务器支持的范围file:///etc/passwd读取文件http://127.0.0.1:22探测本地SSH端口dict://127.0.0.1:6379/info探测Redis如果支持dict协议gopher://127.0.0.1:6379/_...构造Gopher协议攻击Redis绕过尝试如果遇到白名单校验如只允许example.com则使用前述的绕过技术进行测试。4.3 第三步内网探测与端口扫描一旦确认存在SSRF且能访问内网攻击就进入了实质性阶段。识别网络环境首先访问云元数据端点判断是否为云服务器。AWS:http://169.254.169.254阿里云:http://100.100.100.200腾讯云:http://metadata.tencentyun.com构造端口扫描Payload由于SSRF通常是“盲”的看不到直接回显需要根据响应时间、错误信息、响应内容差异来判断端口状态。// 攻击者可能通过Burp Intruder批量尝试 // Payload: http://192.168.1.[1-254]:[80,443,22,3306,6379,8080]连接超时/拒绝端口可能关闭或存在防火墙。立即返回错误如连接被重置端口可能开放但协议不匹配如向80端口发送Redis命令。响应时间较长后返回错误端口可能开放并且服务正在处理非法请求。返回特定服务的Banner信息直接命中例如访问http://192.168.1.10:6379可能返回一个-ERR这正是Redis的响应特征。4.4 第四步漏洞利用与横向移动发现开放端口和服务后攻击者会尝试进一步利用攻击无认证的Web服务访问内网管理后台如http://192.168.1.1/admin、Jenkins、Confluence等可能直接获取控制权。攻击数据库与缓存服务Redis利用SSRFRedis未授权访问可以写入Webshell或计划任务。例如通过gopher协议或HTTP协议走私如果Redis支持HTTP交互发送SET、CONFIG SET等命令。MySQL虽然MySQL协议复杂但通过SSRF进行盲注或利用已知漏洞也是可能的。读取云元数据这是危害最大的一种。获取到临时安全凭证STS Token后攻击者可以使用AWS CLI、阿里云CLI等工具以该服务器的身份操作云资源进行数据窃取、资源滥用甚至环境破坏。组合利用将SSRF作为跳板结合其他漏洞。例如通过SSRF访问内网一个存在Struts2漏洞的应用触发远程命令执行。4.5 第五步数据外带与权限维持在成功利用后攻击者需要将获取的数据如/etc/passwd内容、云元数据、数据库信息外带出来。由于SSRF的响应通常直接返回给前端攻击者可以通过以下方式获取数据直接回显如果服务器将请求的响应内容完整地返回给用户那是最理想的情况。差异响应通过响应时间、长度、状态码的差异来推断信息盲SSRF。DNS外带让服务器请求一个攻击者控制的域名并将数据放在子域名中如http://base64-data.attacker.com通过DNS日志获取数据。HTTP外带类似DNS外带但通过HTTP请求将数据带出。实操心得在渗透测试中验证SSRF时Burp Suite的Collaborator功能是神器。它能帮你接收所有由目标服务器发起的请求DNS HTTP SMTP完美解决“盲”SSRF的验证问题。在代码审计中我们要假设攻击者拥有所有这些工具和技术从而在设计防御时考虑最坏情况。5. Java代码审计实战逐层拆解与防御方案理论说再多不如看代码。我们现在以一个虚拟的“在线文档转换服务”为例进行一场完整的代码审计推演。5.1 审计目标一个文档转换服务接口假设我们审计以下Spring Boot控制器代码RestController RequestMapping(/api/convert) public class DocumentConverterController { Autowired private RestTemplate restTemplate; PostMapping(/fromUrl) public ResponseEntitybyte[] convertFromUrl(RequestParam String sourceUrl) { // 1. 下载源文件 byte[] fileData; try { fileData restTemplate.getForObject(sourceUrl, byte[].class); } catch (RestClientException e) { return ResponseEntity.badRequest().body(Failed to fetch document..getBytes()); } // 2. 调用内部转换引擎假设 byte[] convertedData InternalConverterEngine.convert(fileData); // 3. 返回转换后的文件 return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, attachment; filename\converted.pdf\) .body(convertedData); } }5.2 漏洞点分析入口点sourceUrl参数用户完全可控。请求发起层使用了Spring的RestTemplate。默认情况下RestTemplate会使用SimpleClientHttpRequestFactory它基于JDK的HttpURLConnection。关键缺陷sourceUrl未经任何校验直接传入restTemplate.getForObject。这意味着攻击者可以传入任意协议、任意主机的URL。5.3 攻击模拟攻击者可以发起如下请求POST /api/convert/fromUrl?sourceUrlhttp://169.254.169.254/latest/meta-data/iam/security-credentials/ HTTP/1.1服务器会向AWS元数据服务发起请求并将返回的IAM角色凭证作为“文件数据”返回给攻击者。攻击者下载这个“转换后的文件”就拿到了云服务器的临时密钥。5.4 层层加固从弱到强的防御方案方案一黑名单过滤最弱不推荐// 反例极易绕过 private boolean isMaliciousUrl(String url) { String[] blacklist {127.0.0.1, localhost, 169.254.169.254, 0.0.0.0, file://}; for (String black : blacklist) { if (url.contains(black)) { return true; } } return false; }为什么不行绕过方式太多了127.0.0.1可以用2130706433localhost可以用LOCALHOST大小写file://可以用FILE://或file:///而且黑名单永远列不全。方案二白名单域名校验有所改善但仍有缺陷private boolean isAllowedUrl(String urlString) { try { URL url new URL(urlString); String host url.getHost(); // 只允许来自 example.com 和 trusted.org 的资源 return host.endsWith(.example.com) || host.equals(trusted.org); } catch (MalformedURLException e) { return false; } }优点比黑名单好限定了来源。缺点基于URL.getHost()的校验发生在解析前可能被符号绕过http://trusted.orgevil.com/getHost()返回evil.com但某些老旧客户端可能请求trusted.org实际上规范下getHost()返回evil.com但攻击者可能利用解析差异。无法防御DNS重绑定攻击。evil.com的DNS记录可以先指向trusted.org的IP通过校验再指向内网IP。过于严格限制了业务灵活性。方案三解析后校验默认拒绝推荐方案这是目前业界最主流的防御思路。核心是先将用户输入的字符串解析成网络请求的最终目标IP、端口、协议再对这个目标进行校验。import java.net.InetAddress; import java.net.URI; import java.net.URL; import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; Service public class SsrfProtector { // 允许的协议通常只允许 HTTP/HTTPS private static final ListString ALLOWED_PROTOCOLS Arrays.asList(http, https); // 禁止访问的IP段内网、回环、云元数据等 private static final ListPattern DENIED_IP_PATTERNS Arrays.asList( Pattern.compile(^127\\.\\d\\.\\d\\.\\d$), Pattern.compile(^10\\.\\d\\.\\d\\.\\d$), Pattern.compile(^172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d\\.\\d$), Pattern.compile(^192\\.168\\.\\d\\.\\d$), Pattern.compile(^169\\.254\\.\\d\\.\\d$), Pattern.compile(^0\\.0\\.0\\.0$), Pattern.compile(^::1$), Pattern.compile(^fc00::/7$), // IPv6 私有地址 Pattern.compile(^fe80::/10$) // IPv6 链路本地地址 ); // 可选的域名白名单如果业务需要 private static final ListString ALLOWED_DOMAINS Arrays.asList(cdn.mycompany.com, assets.trusted-partner.com); public URI validateAndGetUri(String urlString) throws SsrfException { URI uri; try { uri new URI(urlString).normalize(); } catch (Exception e) { throw new SsrfException(Invalid URL format.); } // 1. 校验协议 String scheme uri.getScheme(); if (scheme null || !ALLOWED_PROTOCOLS.contains(scheme.toLowerCase())) { throw new SsrfException(Protocol not allowed.); } // 2. 解析主机名到IP地址关键步骤防御DNS重绑定 String host uri.getHost(); if (host null) { throw new SsrfException(Host cannot be determined.); } InetAddress inetAddress; try { // 这里进行DNS解析将域名转换为具体的IP inetAddress InetAddress.getByName(host); } catch (Exception e) { throw new SsrfException(Could not resolve host.); } String ip inetAddress.getHostAddress(); // 3. 校验IP地址是否在禁止范围内 for (Pattern pattern : DENIED_IP_PATTERNS) { if (pattern.matcher(ip).matches()) { throw new SsrfException(Access to internal IP addresses is denied.); } } // 4. 可选如果配置了域名白名单进行二次校验 if (!ALLOWED_DOMAINS.isEmpty()) { boolean domainAllowed ALLOWED_DOMAINS.stream().anyMatch(allowed - host.toLowerCase().endsWith(. allowed.toLowerCase()) || host.equalsIgnoreCase(allowed)); if (!domainAllowed) { throw new SsrfException(Domain not in whitelist.); } } // 5. 返回净化后的URI可选可以重构一个只包含允许内容的URI return uri; } }在业务代码中使用PostMapping(/fromUrl) public ResponseEntitybyte[] convertFromUrl(RequestParam String sourceUrl) { try { // 使用保护器进行校验和解析 URI safeUri ssrfProtector.validateAndGetUri(sourceUrl); // 使用校验后的URI发起请求 byte[] fileData restTemplate.getForObject(safeUri, byte[].class); // ... 后续处理 } catch (SsrfException e) { return ResponseEntity.badRequest().body((Security check failed: e.getMessage()).getBytes()); } }方案四使用安全的HTTP客户端并进行深度配置即使校验了URL客户端的某些行为也可能带来风险。需要对使用的HTTP客户端进行安全加固。以Apache HttpClient为例import org.apache.http.client.config.RequestConfig; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.DefaultSchemePortResolver; import org.apache.http.impl.conn.SystemDefaultRoutePlanner; import java.net.InetSocketAddress; import java.net.ProxySelector; import java.net.URI; // 1. 禁用重定向防止重定向攻击 RequestConfig requestConfig RequestConfig.custom() .setRedirectsEnabled(false) // 关键禁止自动重定向 .setConnectTimeout(5000) .setSocketTimeout(5000) .build(); // 2. 自定义DNS解析器可选用于固定DNS解析彻底防御DNS重绑定但可能影响性能 // 可以在此处实现一个缓存DNS解析器在URL校验阶段解析的IP在请求阶段强制使用确保一致性。 // 3. 创建客户端 CloseableHttpClient httpClient HttpClients.custom() .setDefaultRequestConfig(requestConfig) // .setDnsResolver(myFixedDnsResolver) // 如果实现了固定DNS解析器 .build(); // 使用时将校验后的URI传入 HttpGet request new HttpGet(validatedUri);以Spring RestTemplate为例import org.springframework.http.client.SimpleClientHttpRequestFactory; import java.net.HttpURLConnection; import java.net.URL; SimpleClientHttpRequestFactory requestFactory new SimpleClientHttpRequestFactory() { Override protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException { super.prepareConnection(connection, httpMethod); // 禁用跟随重定向 connection.setInstanceFollowRedirects(false); } }; RestTemplate restTemplate new RestTemplate(requestFactory);方案五网络层隔离与代理策略代码防御是最后一道防线更基础的是架构安全部署隔离将可能触发SSRF的服务部署在独立的安全子网或DMZ中严格限制其出站流量。通过防火墙或安全组策略只允许访问必要的、明确的外部白名单地址和端口。使用出口代理所有从服务器发起的对外请求必须经过一个配置了严格白名单的出口代理。这样即使代码层被绕过网络层也会拦截非法请求。最小权限原则运行Java应用的服务器/容器账号应遵循最小权限原则避免使用root或高权限账号运行减少本地文件读取的危害。6. 高级审计技巧与疑难问题排查在实际审计中会遇到一些更隐蔽或复杂的情况。6.1 处理“盲”SSRF“盲”SSRF是指请求由服务器发出但响应不直接返回给前端攻击者无法直接看到结果。审计时如何发现关注外部依赖调用检查代码中所有发起网络请求的地方即使其返回值未被使用。例如日志上报、 metrics推送、异步回调、消息队列触发等。关注错误信息差异虽然看不到结果但服务器可能因请求成功或失败而返回不同的错误信息、状态码或响应时间。审计时需留意这些“侧信道”。审计日志查看应用日志或访问日志寻找是否有异常的、对内部地址的请求记录。6.2 审计第三方库和SDK现代应用大量使用第三方库。这些库内部也可能发起网络请求。配置加载很多库会从远程URL加载配置如某些XML解析器、日志配置。许可证检查/更新检查一些商业或开源库会“打电话回家”。数据上报统计、监控SDK。审计策略在引入第三方库时应审查其文档和源码如果可能了解其网络行为。在沙箱或测试环境中使用网络抓包工具如Wireshark观察应用启动和运行时的所有网络连接。6.3 自动化审计思路对于大型项目可以借助自动化工具辅助静态代码分析SAST使用Fortify Checkmarx SonarQube等工具可以扫描出常见的SSRF漏洞模式。但需要人工验证误报和漏报。自定义规则扫描使用grep、semgrep或CodeQL编写自定义规则搜索危险函数调用如URL.openConnection()HttpClient.execute()并跟踪其参数来源。交互式应用安全测试IAST在测试环境运行应用结合代理工具进行模糊测试实时检测漏洞。6.4 常见问题排查表在修复或验证SSRF漏洞时你可能会遇到以下问题问题现象可能原因排查步骤与解决方案白名单校验后业务功能异常1. 白名单域名列表不全。2. 域名解析问题如CDN有多级域名。3. URL中包含端口、路径或查询参数校验逻辑过于严格。1. 检查业务日志看被拦截的请求URL是什么。2. 将校验失败的URL加入调试日志分析其host部分。3. 确保校验逻辑只针对host和protocol不涉及端口和路径除非业务有特殊要求。4. 考虑使用更宽松的匹配如子域名匹配。防御代码已添加但漏洞扫描器仍报出SSRF1. DNS重绑定攻击未防御。2. 校验逻辑存在绕过如大小写、特殊字符。3. 应用其他位置存在同类漏洞未修复。4. 扫描器误报。1. 确认防御代码是否包含“解析主机名到IP”并校验IP的步骤。2. 使用扫描器提供的Payload进行手动复现查看具体哪个环节被绕过。3. 在全代码库中搜索所有可能的网络请求发起点。4. 验证扫描器Payload在真实环境中的效果。使用RestTemplate跟随重定向导致绕过RestTemplate默认使用的SimpleClientHttpRequestFactory可能跟随重定向。如5.4节所述自定义RequestFactory并设置connection.setInstanceFollowRedirects(false);。或者使用配置了setRedirectsEnabled(false)的Apache HttpClient。对IPv6地址的拦截失效黑名单或正则表达式只匹配了IPv4格式。在IP黑名单正则中补充IPv6的私有地址和回环地址模式如^::1$^fc00::/7$^fe80::/10$。使用Java的InetAddress类进行解析和判断更可靠。7. 总结构建纵深防御体系通过以上从原理到实战的拆解我们可以看到一个看似简单的SSRF漏洞其挖掘和防御涉及网络编程、协议解析、系统架构、云安全等多个层面的知识。在Java代码审计中绝不能仅仅满足于找到一处getForObject就了事。一个健壮的SSRF防御体系应该是纵深式的第一层输入校验与白名单。在业务逻辑入口对用户输入的URL进行严格的“解析后校验”采用默认拒绝策略只放行明确可信的协议和IP/域名范围。第二层安全的客户端使用。选用安全的HTTP客户端如OkHttp Apache HttpClient并正确配置禁用重定向、设置超时、使用连接池。避免使用底层、难以控制的URL.openStream()。第三层架构与网络隔离。将存在风险的业务部署在独立网络区域通过防火墙策略严格限制出站流量。对所有出站请求使用强制代理并在代理层实施全局白名单策略。第四层运行时监控与响应。建立完善的日志审计机制记录所有对外请求的目标地址、响应状态。设置告警规则对访问内网地址、云元数据地址等异常行为进行实时告警。第五层安全开发意识。将SSRF作为安全编码培训的必修课在代码审查Code Review中重点关注所有发起网络请求的代码。最后分享一个我个人的深刻体会安全不是一个功能而是一种属性。它必须贯穿于软件设计、开发、测试、部署和运维的全生命周期。对于SSRF这类漏洞亡羊补牢的成本远高于未雨绸缪。在写下任何一行会发起网络请求的代码时多问自己一句“这个URL我真的能信任它吗” 养成这个习惯才是从根本上杜绝漏洞的最佳实践。