抓包工具(三)Wireshark代理抓包Java程序的HTTPS请求

news/2025/2/23 16:52:01

目录

    • 一、需求背景
    • 二、操作步骤
      • 2.1 jSSLKeyLog 工具下载
      • 2.2 jSSLKeyLog工具使用
      • 2.3 将sslkeylog导入Wireshark
      • 2.4 测试Demo
      • 2.5 测试结果
        • 1)使用工具解密HTTPS前:
        • 2)实用工具解密HTTPS后:
    • 三、补充:如果出现未解密成功的情况

https://i-blog.csdnimg.cn/direct/387a0b1db92a47ae82a655abc8054a6b.jpeg" width="60%" />

一、需求背景

在上一篇文章中,我们介绍了 Wireshark 抓包工具的基本使用:抓包工具(二)Wireshark 的下载、安装、使用、快捷键。

我们先回顾下:Wireshark 和其他抓包软件相比,优势在于直接在网络传输的物理层 进行抓包,对于本地开发调试程序发送的请求不需要代理也可以抓到。但是缺点就是 无法进行 HTTPS 请求包进行解密

我在网上找了很多篇文章,其实使用 Wireshark 进行 HTTPS 的 TLS流 进行解密 无非以下两种方式</:

  • 方法一:拿到服务器的 .p12 证书文件(含私钥信息),导入 Wireshark。

    这种方式除非是服务器的维护人员,否则一般情况下是拿不到的,而且拿出来之后的证书可以直接伪造网站信息,非常不安全。

  • 方法二:通过设置浏览器的启动参数,或者添加 SSLKEYLOGFILE 环境变量,记录到 HTTPS 加解密过程的日志文件,导入 Wireshark。

    这种方式一般仅适用于浏览器请求抓包。

今天,小编遇到了一个 JDK 小版本的请求问题,想抓包一下不同 JDK 版本的请求内容,以上两种方法都不适用,那怎么办呢?先看效果:

(注意:只有 TLS流HTTP流 是可以解密出来的,TCP流 则是无法解密的,不要追踪错了流类型。)

https://i-blog.csdnimg.cn/direct/bc6985355eb6416dbf54882292664e82.png" alt="在这里插入图片描述" />

补充: 如果让 Java 程序走 Fiddler4 的代理也可以成功抓包,但是小编的情况比较特殊,走了 Fiddler4 的代理之后,问题就无法复现了。推测是 Fiddler4 对于请求内容进行了兼容调整,所以还得是 Wireshark 出马。


二、操作步骤

2.1 jSSLKeyLog 工具下载

我们都知道,一个完整的 HTTP 请求过程中会经历 三次握手四次挥手

上面我们介绍过的方法二其实就是通过收集 “三次握手” 过程中生成的 sslkeylog 密钥进行解密。这里我们同样也需要使用工具获取用来解密的密钥,如下所示:

  • jSSLKeyLog: https://github.com/jsslkeylog/jsslkeylog

官方介绍如下:

jSSLKeyLog 是一个 Java Agent 库,它可以将 Java 应用程序创建的 SSL 会话密钥记录到 Wireshark 可识别的日志文件中,从而可以通过 “跟踪 SSL 数据流” 功能调试 SSL 连接问题,就像连接未加密一样。它既适用于 Java 服务器软件,也适用于客户端软件。

(注意:jSSLKeyLog 工具要求环境在 JDK 7 及以上)

  • 官网下载: https://github.com/jsslkeylog/jsslkeylog/releases

如果是 JDK8 可以直接使用下面这个文件,小编亲测好用。

  • JDK8版本jSSLKeyLog下载: https://share.weiyun.com/h2i2oVns

文件如下所示:

https://i-blog.csdnimg.cn/direct/c92e2e636ff5454992f594ff359ec718.png" alt="在这里插入图片描述" />

2.2 jSSLKeyLog工具使用

使用时,我们只需要在启动命令加上如下参数即可:

-javaagent:D:\java\jSSLKeyLog.jar=D:\sslkeylog.txt

  • D:\java\jSSLKeyLog.jar:工具包位置。
  • D:\sslkeylog.txt:希望生成的SSL密钥文件位置。

如果是在 IDEA 中启动 Java 程序,可以在启动配置中先选择 Add VM options

https://i-blog.csdnimg.cn/direct/39fe64bf007044f28029e3ac196653fe.png" alt="在这里插入图片描述" />

然后添加启动参数,如下所示:

https://i-blog.csdnimg.cn/direct/889f260dc4e94942b5caf003a778bcdd.png" width="40%" />

自动生成的 sslkeylog.txt 日志文件内容如下所示:

https://i-blog.csdnimg.cn/direct/308ecf8348494d55890431c3c9aab939.png" alt="在这里插入图片描述" />

2.3 将sslkeylog导入Wireshark

打开 Wireshark,点击 编辑,再点击 首选项

https://i-blog.csdnimg.cn/direct/d5f35f0cb47141daaed5f47cfce3fe0f.png" width="60%" />

Protocols 中选择 TLS 协议,再选择我们刚才生成的 sslkeylog.txt 文件,点击确定即可。

https://i-blog.csdnimg.cn/direct/2e318db2b6d74d858ca9c4e063037226.png" width="60%" />

随后选择需要进行抓包的网卡,即可进行抓包。

2.4 测试Demo

这里我们以一个HTTPS测试网站 httpbin 为例进行请求,地址如下:

  • 页面地址: https://httpbin.org/#/Anything/post_anything
  • 接口地址: https://httpbin.org/anything

Wireshark筛选规则:

  • src or dst host httpbin.org

代码示例:

  • 启动参数:-javaagent:D:\java\jSSLKeyLog.jar=D:\sslkeylog.txt
java">package com.demo.example;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * <p> @Title Test
 * <p> @Description Wireshark抓包工具Demo
 *
 * @author ACGkaka
 * @date 2025/2/22 21:56
 */
public class Test {

    public static void main(String[] args) {
        String url = "https://httpbin.org/anything";
        String param = "{\"appKey\":\"7844ed27528aa2e1b7a6a2878484ad4c\",\"userPhone\":\"155****8888\"}";
        System.out.println("===> 请求地址:" + url + ",请求内容:" + param);

        String result = doPostByJson(url, param);
        System.out.println("<== 响应结果:" + result);
    }

    /**
     * POST请求,JSON传参
     */
    public static String doPostByJson(String urlPath, String json) {
        OutputStream outputStream = null;
        BufferedReader reader = null;
        try {
            // 信任所有Hosts(HTTPS专用)
            trustAllHosts();

            // 1、建立连接
            HttpURLConnection conn;
            URL url = new URL(urlPath);
            if (url.getProtocol().equalsIgnoreCase("https")) {
                HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
                httpsConn.setHostnameVerifier(DO_NOT_VERIFY);
                conn = httpsConn;
            } else {
                conn = (HttpURLConnection) url.openConnection();
            }
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("Charset", "UTF-8");
            conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            conn.setRequestProperty("accept", "application/json");

            // 2、写入请求体
            byte[] writebytes = json.getBytes();
            conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
            outputStream = conn.getOutputStream();
            outputStream.write(json.getBytes());
            outputStream.flush();
            outputStream.close();

            // 3、读取响应
            InputStream inputStream = conn.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream));
            String line = reader.readLine();
            StringBuffer response = new StringBuffer();
            while (line != null) {
                response.append(line);
                line = reader.readLine();
                if (line != null) {
                    response.append("\n");
                }
            }
            reader.close();
            return response.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    System.out.println("输出流关闭失败");
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    System.out.println("输入流关闭失败");
                }
            }
        }
        return null;
    }

    // --------------------------------------------------------------------------------------------------------------
    // 私有方法
    // --------------------------------------------------------------------------------------------------------------

    /**
     * 信任所有Hosts(HTTPS专用)
     *
     * (补充:如果服务器使用的SSL证书不是由Java默认信任的证书颁发机构(CA)签发的,例如自签名证书,就会报错:
     *      SunCertPathBuilderException: unable to find valid certification path to requested target。)
     */
    private static void trustAllHosts() {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[]{};
            }
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
        }
        };

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * HostnameVerifier 接口用于验证HTTPS连接的主机名是否与证书中的主机名匹配。
     *
     * (补充:当Java应用程序尝试建立HTTPS连接时,它会检查服务器的SSL证书以确保其有效性,
     *      并且还会检查证书中的主机名是否与正在连接的实际主机名相匹配。如果主机名不匹配,
     *      默认情况下连接会被拒绝,从而保护应用程序不受潜在的安全威胁。)
     */
    private final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        public boolean verify(String arg0, SSLSession arg1) {
            return true;
        }
    };
}

2.5 测试结果

1)使用工具解密HTTPS前:

如下图所示:

  1. 完全看不到HTTP流信息。
  2. Application Data 请求内容为密文乱码,无法查看。

https://i-blog.csdnimg.cn/direct/a5d7697457344c66a37c65fe2d5fddb1.png" alt="在这里插入图片描述" />

在 Application Data 右键,点击 追踪流,选择 TLS Stream,看到的也是一团密文乱码,如下所示:

https://i-blog.csdnimg.cn/direct/f8fb841457dc4a47be2a1d2c0946494e.png" width="60%" /> https://i-blog.csdnimg.cn/direct/911b148914574c48abce06438d24f086.png" width="60%" />
2)实用工具解密HTTPS后:

如下图所示,解析后的 HTTP流 显示出来了,而且内容为明文可见。

https://i-blog.csdnimg.cn/direct/8dac3cc154a04af687d206536c6c6cee.png" alt="在这里插入图片描述" />

在 Application Data 右键,点击 追踪流,选择 TLS Stream,看到的也是清晰的明文,如下所示:

https://i-blog.csdnimg.cn/direct/32feadd45d8b4fdf8c905136bb1ad1e7.png" width="60%" />

三、补充:如果出现未解密成功的情况

如下图所示,如果出现 [TCP Retransmission]TCP Previous segment not captured][TCP Out-Of-Order] 这种情况,我们只需要清掉已经抓包内容,重启 Wireshark 程序进行重新抓包即可恢复:

https://i-blog.csdnimg.cn/direct/b9bbf89fb69c44acb9c483785590a814.png" alt="在这里插入图片描述" />

整理完毕,完结撒花~🌻





参考地址:

1.wireshark分析httpsjavaagent获取jsslkeylog进行解码,https://blog.csdn.net/zhaikaiyun/article/details/125366481


http://www.niftyadmin.cn/n/5863597.html

相关文章

[创业之路-321]:创新开拓思维和经营管理思维的比较

目录 一、概述 1.1、定义与内涵 1、创新开拓思维&#xff1a; 2、经营管理思维&#xff1a; 1.2、特点与优势 1、创新开拓思维的特点与优势&#xff1a; 2、经营管理思维的特点与优势&#xff1a; 3、应用场景与限制 4、总结 二、创新开拓思维与经营管理思维&#xf…

C++STL容器之list

1.介绍 list是标准模版库&#xff08;STL&#xff09;提供的一个双向链表容器。它允许在常数时间内进行插入或删除操作&#xff0c;但不支持随机访问。&#xff08;即不能通过下边直接访问元素&#xff09;。list是一个序列容器&#xff0c;适合需要频繁插入和删除操作的场景。…

大规模 RDMA AI 组网技术创新:算法和可编程硬件的深度融合

目录 文章目录 目录大规模 RDMA 组网挑战算法和硬件深度融合拥塞控制算法方面的创新硬件卸载方面的创新 微软云 DCQCN 量化拥塞通知谷歌云 TIMELY 基于 RTT 的拥塞控制阿里云 HPCC 高精度拥塞控制AWS SRD 可扩展的可靠数据报协议 大规模 RDMA 组网挑战 随着 AI 大模型技术的兴…

Redis 基础命令 --- ZSet篇

实验环境 redis版本: 7.0.4一. 概述 Redis的ZSet是一个可排序的Set集合&#xff0c;ZSet中的每一个元素都带有一个score属性&#xff0c;可以基于score属性对元素排序&#xff0c;集合成员是唯一的&#xff0c;但是评分可以重复。 ZSet具备下列特性&#xff1a; 可排序元素…

代码随想录D52-53 图论 Python

目录 101. 孤岛的总面积 102. 沉没孤岛 103. 水流问题 104. 建造最大岛屿 101. 孤岛的总面积 要点&#xff1a; 整体来说是一个图着色的问题。 这道题目的思路符合直觉&#xff0c;但代码实现会和直觉有差别。如果仅使用visit记录不使用着色&#xff0c;会遇到非常多的…

免填邀请码工具:赋能六大核心场景,重构App增长新模型

在移动互联网流量红利逐渐消退的当下&#xff0c;用户转化漏斗中的每个环节都直接影响着App的商业价值。openinstall的免填邀请码工具&#xff0c;通过深度整合渠道归因与轻量化SDK方案&#xff0c;在用户首次打开App时即完成关键信息匹配&#xff0c;重构了传统用户增长模型。…

利用Postman和Apipost进行WebSocket调试和文档设计

在现代 Web 开发中&#xff0c;Websocket 作为一种常见的 Web 协议&#xff0c;与 Restful API 有着本质的不同。Restful API是基于请求-响应模式的单向通信&#xff0c;而 WebSocket 提供全双工通信渠道&#xff0c;允许客户端和服务器之间进行实时双向数据传输。这种特性使得…

MapReduce理论知识与实践

1. 什么是MapReduce MapReduce是一种分布式计算模型&#xff0c;用于处理大量数据。它由Google提出&#xff0c;广泛应用于大数据处理平台&#xff08;如Hadoop&#xff09;。MapReduce模型的核心思想是将任务分解成两个阶段&#xff1a;Map阶段和Reduce阶段。 Map阶段&#x…