java 代码审计 - SSRF

SSRF(Server-Side Request Forgery,服务器端请求伪造)是一种由攻击者构造形成由服务器端发起请求的安全漏洞。攻击者能够利用受影响的应用程序,发送伪造的 HTTP 请求,使其伪装成服务器内部发起的请求,从而能够直接或间接地访问或控制应用程序无意中暴漏的受保护资源。

        Web 应用程序往往会提供一些能够从远程获取图片或是文件的接口,在这些接口上用户使用指定的 URL 便能完成远程获取图片、下载文件等操作。攻击者可以通过使用file协议来读取服务器本地/etc/passwd/proc/self/cmdline等敏感文件,同时攻击者也可以利用被攻击的服务器绕过防火墙直接对处于内网的机器发起进一步的攻击。

原理

        SSRF 漏洞的本质是服务端提供了从其他应用服务器获取数据的功能,但没有对目标地址做过滤与限制。攻击者通过向应用程序发送特定的请求,传入一个用户可控的参数作为目标 URL 或者 IP 地址,进行实现对受害系统内部任意资源的访问。

支持的协议

        在 Java(JDK21)中,SSRF 支持sun.net.www.protocol下所有的协议:fileftphttphttpsjarjmodjrtmailto协议。这些是 JDK 内置的、通过 URL 类直接支持的标准协议,但在生产代码中应始终使用标准的java.netAPI,避免直接依赖sun.*包。

图片

        由于上述协议的限制,以及传入的 URL 协议必须和重定向后的 URL 协议一致的原因,使得 Java 中的 SSRF 并不能像 PHP 中一样使用gopher协议来拓展攻击面。

  1. file - 本地文件系统协议
  • URL 示例:file:///etc/passwd
  • 作用:用于访问本地文件系统中的文件。
  1. ftp - 文件传输协议
  • URL 示例:ftp://user:[email protected]/pub/file.txt
  • 作用:通过 FTP 协议下载或上传文件。
  1. http - 超文本传输协议
  • URL 示例:http://example.com/index.html
  • 作用:获取 Web 资源。
  1. https - 安全超文本传输协议
  • URL 示例:https://example.com/api/user
  • 作用:获取 Web 资源。
  1. jar - JAR 文件协议
  • URL 示例:jar:file:///app/lib/utils.jar!/config.properties
  • 作用:访问 JAR 包内部的资源文件。
  1. jmod - JMOD 文件协议(JDK 9+)
  • URL 示例:jmod:/path/to/module.jmod!/resources/file.txt
  • 作用:用于访问 .jmod 文件中的内容。
  1. jrt - 运行时镜像协议(JDK 9+)
  • URL 示例:jrt:/java.base/java/lang/Object.class
  • 作用:访问 运行时模块镜像(Run-Time Image) 中的类和资源。
  1. mailto - 邮件协议
  • URL 示例:mailto:[email protected]?subject=Hello&body=Hi!
  • 作用:启动默认邮件客户端,预填收件人、主题、正文等。

常见发起网络请求,并产生 SSRF 漏洞写法

urlConnection

urlConnection类是 Java 中用于发起网络请求的基础类,它是一个抽象类,通过java.net.URL类的openConnection()方法来获取其实例。表示指向 URL 指定资源的活动链接,它有两个直接子类,分别是HttpURLConnectionJarURLConnection。在默认情况下,urlConnection的参数没有有效控制时会引起 SSRF 漏洞。

package com.ssrf.vuln.ssrfdemo.Servlet; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; @WebServlet(name = "Ssrf1Servlet", urlPatterns = "/ssrf1") public class Ssrf1Servlet extends HttpServlet {     @Override     protected void doGet(HttpServletRequest req, HttpServletResponse resp)             throws IOException {         resp.setContentType("text/html; charset=utf-8");         String urlString = req.getParameter("url");         if (urlString == null || urlString.isEmpty()) {             resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);             resp.getWriter().write("URL 参数不能为空");             return;         }         try {             // 1. 创建 URL 对象             URL url = new URL(urlString);             // 2. 打开连接,获取 URLConnection 对象             URLConnection urlConnection = url.openConnection();             // 3. 读取响应             BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));             StringBuilder content = new StringBuilder();             String line;             while ((line = in.readLine()) != null) {                 content.append(line);             }             in.close();             resp.getWriter().write(content.toString());         } catch (IOException e) {             resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);             resp.getWriter().write("无法访问指定的URL");         }     } } 

图片

图片

HttpURLConnection

HttpURLConnectionjava.net包中的一个类,它继承自URLConnection类,专门用于处理 HTTP 协议的连接。

它可以发送 GET 请求与 POST 请求。同样的,在没有过滤的默认情况下其会产生 SSRF 漏洞。

package com.ssrf.vuln.ssrfdemo.Servlet; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; @WebServlet(name = "Ssrf2Servlet", urlPatterns = "/ssrf2") public class Ssrf2Servlet extends HttpServlet {     @Override     protected void doGet(HttpServletRequest req, HttpServletResponse resp)             throws IOException {         resp.setContentType("text/html; charset=utf-8");         String urlString = req.getParameter("url");         if (urlString == null || urlString.isEmpty()) {             resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);             resp.getWriter().write("URL 参数不能为空");             return;         }         try {             // 创建 URL 对象             URL url = new URL(urlString);             // 打开连接,并转换为 HttpURLConnection             HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();             // 设置请求方法             urlConnection.setRequestMethod("GET");             // 设置连接超时时间             urlConnection.setConnectTimeout(5000);             // 设置读取超时时间             urlConnection.setReadTimeout(5000);             // 检查响应码             int responseCode = urlConnection.getResponseCode();             if (responseCode != HttpURLConnection.HTTP_OK) {                 resp.setStatus(HttpServletResponse.SC_NOT_FOUND);                 resp.getWriter().write("无法访问指定的URL,响应码:" + responseCode);                 return;             }             // 读取数据             BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));             StringBuilder content = new StringBuilder();             String inputLine;             while ((inputLine = in.readLine()) != null) {                 content.append(inputLine);             }             in.close();             // 返回实际内容             resp.getWriter().write(content.toString());         } catch (Exception e) {             // 捕获异常             resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);             resp.getWriter().write("发生错误: " + e.getMessage());         }     } } 

Apache HttpClient - Request

Request是是一个基于 Apache HttpClient 的高级封装,提供了更简洁、流畅的 API 来发起 HTTP 请求。在没有过滤的默认情况下会产生 SSRF 漏洞。

<dependency>   <groupId>org.apache.httpcomponents.client5</groupId>   <artifactId>httpclient5-fluent</artifactId>   <version>5.5.1</version> </dependency> 
package com.ssrf.vuln.ssrfdemo.Servlet; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.apache.hc.client5.http.fluent.Content; import org.apache.hc.client5.http.fluent.Request; import java.io.IOException; @WebServlet(name = "Ssrf3Servlet", urlPatterns = "/ssrf3") public class Ssrf3Servlet extends HttpServlet {     @Override     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {         String urlParam = req.getParameter("url");         // 创建请求         Request request = Request.get(urlParam);         // 执行请求         Content content = request.execute().returnContent();         String responseBody = content.asString();         // 输出响应         resp.getWriter().write(responseBody);     } } 

图片

HttpClient

HttpClient 是 Apache Jakarta Common 下的一个流行的开源 HTTP 客户端库,它不仅支持 HTTP 协议,还支持 HTTPS、代理、Cookie 管理、身份验证等功能。在默认情况下,其也会产生 SSRF 漏洞。

package com.ssrf.vuln.ssrfdemo.Servlet; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.client5.http.classic.methods.HttpGet; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @WebServlet(name = "Ssrf4Servlet", urlPatterns = "/ssrf4") public class Ssrf4Servlet extends HttpServlet {     private static final CloseableHttpClient httpClient = HttpClients.createDefault();     @Override     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {         String urlParam = req.getParameter("url");         // 创建请求         HttpGet hg = new HttpGet(urlParam);         // 执行请求         CloseableHttpResponse hResp = httpClient.execute(hg);         // 读取响应         BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(hResp.getEntity().getContent()));         String line;         StringBuilder stringBuilder = new StringBuilder();         while ((line = bufferedReader.readLine()) != null) {             stringBuilder.append(line);         }         // 输出响应         resp.setContentType("text/html;charset=utf-8");         resp.getWriter().write(stringBuilder.toString());     } } 

URL/openStream/ImageIO

java.net.URL包是 Java 标准库中用于处理 URL 的类和接口的包。URL 是用于标识和定位资源的字符串,通常包括协议(如HTTPFTP 等)和资源的位置信息(如域名或 IP 地址、端口、路径等)。java.net.URL包提供了创建、解析、查询和操作 URL 的类和方法。

通过 URL 对象的openStream()方法,能够得到指定资源的输入流。这时如果 URL 对象可控,则会产生 SSRF 漏洞。

ImageIO是 Java 标准库javax.imageio包中的一个核心类,它提供了一组静态方法,用于执行图像的读取、写入、获取格式信息等基本 I/O 操作。

package com.ssrf.vuln.ssrfdemo.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.imageio.ImageIO; import java.awt.*; import java.io.BufferedReader; import java.io.IOException; import java.net.URL; @RestController public class UrlController {     @GetMapping("/ssrf5")     public String UrlOpenStream(@RequestParam String url) throws IOException {         URL u = new URL(url);         BufferedReader in = new BufferedReader(new java.io.InputStreamReader(u.openStream()));         String inputLine;         StringBuilder r = new StringBuilder();         while ((inputLine = in.readLine()) != null) {             r.append(inputLine);         }         in.close();         return r.toString();     }     @GetMapping("/ssrf6")     public String UrlImageIO(@RequestParam String url) throws IOException {         URL u = new URL(url);         Image image = ImageIO.read(u);         return  image.toString();     } } 

图片

源码审计关键词

SSRF 漏洞 URL 中常出现urlffilepage 等参数。程序会发起 HTTP 请求获取远程资源、分享、收藏等操作,因此代码审计时要特别留意能够发起 HTTP 请求的类及函数。:

  • HttpClient.execute
  • HttpClient.executeMethod
  • HttpURLConnection.connect
  • HttpURLConnection.getInputStream
  • URL.openStream
  • URLConnection.getInputStream
  • Request.Get.execute
  • Request.Post.execute
  • ImageIO.read
  • OkHttpClient.newCall.execute
  • HttpServletRequest
  • BasicHttpRequest
  • HttpURLConnection.getInputStream

Solr  SSRF 漏洞审计

漏洞背景简述

  • 漏洞编号:CVE-2021-27905
  • 影响版本:7.0.0 ~ 7.7.3, 8.0.0 ~ 8.8.1
  • solr 下载:https://archive.apache.org/dist/lucene/solr/

Read more

Flutter for OpenHarmony:stomp_dart_client 打造实时消息引擎(企业级 WebSocket 通信标准) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:stomp_dart_client 打造实时消息引擎(企业级 WebSocket 通信标准) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在现代 App 中,“实时通信”已成标配(IM 聊天、股票行情、订单状态推送)。 虽然 WebSocket 协议提供了全双工通信的通道,但它只是 TCP 之上的一个薄层,缺乏“消息路由”、“订阅/发布”等高级语义。 STOMP (Simple Text Oriented Messaging Protocol) 是一种基于文本的消息协议,它定义了 CONNECT, SUBSCRIBE, SEND 等命令,常与 Spring Boot 后端(Spring WebSocket)配合使用。 stomp_dart_client 是 Flutter

By Ne0inhk
Flutter for OpenHarmony: Flutter 三方库 cryptography 在鸿蒙上实现金融级现代加解密(高性能安全库)

Flutter for OpenHarmony: Flutter 三方库 cryptography 在鸿蒙上实现金融级现代加解密(高性能安全库)

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 在开发 OpenHarmony 涉及用户隐私、支付或核心机密的 App 时,基础的 Base64 或简单的 MD5 已经无法满足安全需求。我们需要的是国际标准的现代密码学算法,如 AES-GCM、ChaCha20、ED25519 等。 cryptography 是目前 Flutter 生态中最推荐的现代密码学库。它不仅提供了极其丰富的算法实现,更关键的是它支持“分块处理”和“异步运算”,非常适合在鸿蒙设备上处理大文件加密。 一、核心加密体系解析 cryptography 采用了强类型的 API 设计,确保你不会错误地组合不兼容的参数。 原始敏感数据 (uint8list) Cipher (如 AesGcm) 多线程运算 (Isolate) 密文 + Nonce + MAC

By Ne0inhk

Flutter 三方库 eip55 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、严谨、符合 Web3 标准的以太坊地址校验与防串改引擎

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 eip55 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、严谨、符合 Web3 标准的以太坊地址校验与防串改引擎 在鸿蒙(OpenHarmony)系统的区块链钱包应用、数字资产管理工具(如鸿蒙版 NFT 浏览器)或需要处理加密货币转账的场景中,如何确保用户输入的以太坊(Ethereum)地址既符合基本格式,又通过了大小写混合的校验和(Checksum)验证,防止因为单个字符手误导致的资产永久丢失?eip55 为开发者提供了一套工业级的、基于 EIP-55 提案的地址转换与验证方案。本文将深入实战其在鸿蒙 Web3 安全基座中的应用。 前言 什么是 EIP-55?它是由以太坊创始人 Vitalik Buterin 提出的地址校验和提案。通过在地址字符串中引入特定的。大小写混合模式(基于 Keccak-256 哈希)

By Ne0inhk

M系列Mac保姆级教程:Clawdbot安装+API配置,30分钟解锁AI自动化!

前言 Clawdbot作为超实用的AI自动化工具,能帮你实现网页自动操控、办公流程自动化、本地文件管理等功能,搭配M系列Mac的低功耗特性,堪称效率神器!很多Mac用户安装时会遇到「架构不兼容」「API配置失败」「插件加载报错」等问题,这篇教程专为M4/M1-M3芯片MacBook定制,全程ARM原生适配,从环境准备到功能验证一步到位,新手也能轻松上手~ 一、安装前准备(必看!避坑核心) 1. 系统与工具要求 * 系统版本:macOS 13 Ventura 及以上(M4芯片默认满足,低于该版本先升级:系统设置→通用→软件更新) * 核心依赖:Node.js ≥ 22(必须ARM架构版,避免转译卡顿) * 辅助工具:终端(Launchpad→其他→终端)、Chrome浏览器(ARM原生版) * 网络:需访问外网(对接Claude/Gemini)

By Ne0inhk