SSRF in Java
字数 930 2025-08-29 08:31:41

Java SSRF漏洞分析与防护指南

1. SSRF漏洞概述

SSRF(Server-side Request Forge, 服务端请求伪造)是一种由攻击者构造恶意链接传给服务端执行造成的漏洞,主要用于外网探测或攻击内网服务。

2. Java网络请求支持的协议

Java不像PHP有cURL,支持的协议需要通过以下方式检测:

  • 代码中遍历协议
  • 官方文档查看
  • 通过import sun.net.www.protocol查看

Java支持以下协议:

  • file
  • ftp
  • mailto
  • http
  • https
  • jar
  • netdoc

3. Java中发起网络请求的类

3.1 仅支持HTTP/HTTPS协议的类

  • HttpClient
  • Request (HttpClient封装类)
  • HttpURLConnection
  • okhttp

3.2 支持所有协议的类

  • URLConnection
  • URL

4. 典型漏洞代码示例

@RequestMapping("/download")
@ResponseBody
public void downLoadImg(HttpServletRequest request, HttpServletResponse response) throws IOException{
    try {
        String url = request.getParameter("url");
        if (StringUtils.isBlank(url)) {
            throw new IllegalArgumentException("url异常");
        }
        downLoadImg(response, url);
    }catch (Exception e) {
        throw new IllegalArgumentException("异常");
    }
}

private void downLoadImg (HttpServletResponse response, String url) throws IOException {
    InputStream inputStream = null;
    OutputStream outputStream = null;
    try {
        String downLoadImgFileName = Files.getNameWithoutExtension(url)+"."+Files.getFileExtension(url);
        response.setHeader("content-disposition", "attachment;fileName=" + downLoadImgFileName);
        URL u;
        int length;
        byte[] bytes = new byte[1024];
        u = new URL(url);
        inputStream = u.openStream();
        outputStream = response.getOutputStream();
        while ((length = inputStream.read(bytes)) > 0) {
            outputStream.write(bytes, 0, length);
        }
    }catch (Exception e) {
        e.printStackTrace();
    }finally {
        if (inputStream != null) {
            inputStream.close();
        }
        if (outputStream != null) {
            outputStream.close();
        }
    }
}

5. SSRF利用方式

5.1 直接利用

  • 利用file协议读取任意文件:

    curl -v 'http://localhost:8080/download?url=file:///etc/passwd'
    
  • 利用http/https协议进行端口探测

5.2 302跳转尝试

Java对302跳转有以下限制:

  1. 实际跳转的url必须在支持的协议内
  2. 传入的url协议必须和重定向的url协议一致

因此无法通过302跳转到gopher协议绕过限制。

6. 白盒检测规则

检测以下四种情况的代码:

  1. Request类发起请求:
Request.Get(url).execute()
  1. URL类的openStream方法:
URL u = new URL(url);
inputStream = u.openStream();
  1. HttpClient发起请求:
String url = "http://127.0.0.1";
CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = client.execute(httpGet);
  1. URLConnection和HttpURLConnection:
URLConnection urlConnection = url.openConnection();
HttpURLConnection urlConnection = url.openConnection();

7. 漏洞修复方案

7.1 修复原则

  1. 限制协议为HTTP、HTTPS协议
  2. 禁止URL传入内网IP或设置URL白名单
  3. 无需限制302重定向

7.2 修复代码实现

添加Guava库依赖(用于获取一级域名):

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>21.0</version>
</dependency>

验证逻辑:

String[] urlwhitelist = {"joychou.org", "joychou.me"};
if (!securitySSRFUrlCheck(url, urlwhitelist)) {
    return;
}

安全验证函数:

public static Boolean securitySSRFUrlCheck(String url, String[] urlwhitelist) {
    try {
        URL u = new URL(url);
        // 只允许http和https的协议通过
        if (!u.getProtocol().startsWith("http") && !u.getProtocol().startsWith("https")) {
            return false;
        }
        // 获取域名,并转为小写
        String host = u.getHost().toLowerCase();
        // 获取一级域名
        String rootDomain = InternetDomainName.from(host).topPrivateDomain().toString();
        
        for (String whiteurl: urlwhitelist){
            if (rootDomain.equals(whiteurl)) {
                return true;
            }
        }
        return false;
    } catch (Exception e) {
        return false;
    }
}

8. 总结

Java SSRF漏洞的主要特点:

  • 支持的协议有限,但包含危险的file协议
  • 302跳转有严格限制,难以利用跳转绕过
  • 主要风险来自URL和URLConnection类的使用
  • 修复方案应结合协议限制和域名白名单

通过严格的协议限制和域名白名单验证,可以有效防护Java应用中的SSRF漏洞。

Java SSRF漏洞分析与防护指南 1. SSRF漏洞概述 SSRF(Server-side Request Forge, 服务端请求伪造)是一种由攻击者构造恶意链接传给服务端执行造成的漏洞,主要用于外网探测或攻击内网服务。 2. Java网络请求支持的协议 Java不像PHP有cURL,支持的协议需要通过以下方式检测: 代码中遍历协议 官方文档查看 通过 import sun.net.www.protocol 查看 Java支持以下协议: file ftp mailto http https jar netdoc 3. Java中发起网络请求的类 3.1 仅支持HTTP/HTTPS协议的类 HttpClient Request (HttpClient封装类) HttpURLConnection okhttp 3.2 支持所有协议的类 URLConnection URL 4. 典型漏洞代码示例 5. SSRF利用方式 5.1 直接利用 利用file协议读取任意文件: 利用http/https协议进行端口探测 5.2 302跳转尝试 Java对302跳转有以下限制: 实际跳转的url必须在支持的协议内 传入的url协议必须和重定向的url协议一致 因此无法通过302跳转到gopher协议绕过限制。 6. 白盒检测规则 检测以下四种情况的代码: Request类发起请求: URL类的openStream方法: HttpClient发起请求: URLConnection和HttpURLConnection: 7. 漏洞修复方案 7.1 修复原则 限制协议为HTTP、HTTPS协议 禁止URL传入内网IP或设置URL白名单 无需限制302重定向 7.2 修复代码实现 添加Guava库依赖(用于获取一级域名): 验证逻辑: 安全验证函数: 8. 总结 Java SSRF漏洞的主要特点: 支持的协议有限,但包含危险的file协议 302跳转有严格限制,难以利用跳转绕过 主要风险来自URL和URLConnection类的使用 修复方案应结合协议限制和域名白名单 通过严格的协议限制和域名白名单验证,可以有效防护Java应用中的SSRF漏洞。