目录
- 一、需求背景
- 二、操作步骤
- 2.1 jSSLKeyLog 工具下载
- 2.2 jSSLKeyLog工具使用
- 2.3 将sslkeylog导入Wireshark
- 2.4 测试Demo
- 2.5 测试结果
- 1)使用工具解密HTTPS前:
- 2)实用工具解密HTTPS后:
- 三、补充:如果出现未解密成功的情况
一、需求背景
在上一篇文章中,我们介绍了 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="在这里插入图片描述" />
然后添加启动参数,如下所示:
自动生成的 sslkeylog.txt 日志文件内容如下所示:
https://i-blog.csdnimg.cn/direct/308ecf8348494d55890431c3c9aab939.png" alt="在这里插入图片描述" />
2.3 将sslkeylog导入Wireshark
打开 Wireshark,点击 编辑
,再点击 首选项
。
在 Protocols
中选择 TLS
协议,再选择我们刚才生成的 sslkeylog.txt 文件,点击确定即可。
随后选择需要进行抓包的网卡,即可进行抓包。
2.4 测试Demo
这里我们以一个HTTPS测试网站 httpbin
为例进行请求,地址如下:
Wireshark筛选规则:
src or dst host httpbin.org
代码示例:
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前:
如下图所示:
- 完全看不到HTTP流信息。
Application Data
请求内容为密文乱码,无法查看。
https://i-blog.csdnimg.cn/direct/a5d7697457344c66a37c65fe2d5fddb1.png" alt="在这里插入图片描述" />
在 Application Data 右键,点击 追踪流
,选择 TLS Stream
,看到的也是一团密文乱码,如下所示:
2)实用工具解密HTTPS后:
如下图所示,解析后的 HTTP流 显示出来了,而且内容为明文可见。
https://i-blog.csdnimg.cn/direct/8dac3cc154a04af687d206536c6c6cee.png" alt="在这里插入图片描述" />
在 Application Data 右键,点击 追踪流
,选择 TLS Stream
,看到的也是清晰的明文,如下所示:
三、补充:如果出现未解密成功的情况
如下图所示,如果出现 [TCP Retransmission]
、TCP Previous segment not captured]
、[TCP Out-Of-Order]
这种情况,我们只需要清掉已经抓包内容,重启 Wireshark 程序进行重新抓包即可恢复:
https://i-blog.csdnimg.cn/direct/b9bbf89fb69c44acb9c483785590a814.png" alt="在这里插入图片描述" />
整理完毕,完结撒花~🌻
参考地址:
1.wireshark分析https之javaagent获取jsslkeylog进行解码,https://blog.csdn.net/zhaikaiyun/article/details/125366481