【问题标题】:how to Capture https with fiddler, in java如何在 java 中使用 fiddler 捕获 https
【发布时间】:2012-01-22 21:35:28
【问题描述】:

我在 Eclipse IDE 中运行以下 java 程序:

import java.net.*;
import java.io.*;

public class HH
{
    public static void main(String[] args) throws Exception
    {
        //if i comment out the system properties, and don't set any jvm arguments, the program runs and prints out the html fine.
        System.setProperty("http.proxyHost", "localhost"); 
        System.setProperty("http.proxyPort", "8888"); 
        System.setProperty("https.proxyHost", "localhost"); 
        System.setProperty("https.proxyPort", "8888"); 

        URL x = new URL("https://www.google.com");
        HttpURLConnection hc = (HttpURLConnection)x.openConnection();

        hc.setRequestProperty("User-Agent","Mozilla/5.0 (Windows NT 6.0)
        AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2");

        InputStream is = hc.getInputStream();

        int u = 0;
        byte[] kj = new byte[1024];
        while((u = is.read(kj)) != -1)
        {
            System.out.write(kj,0,u);
        }
        is.close();
    }
}

如果 fiddler 在捕获和不捕获时都在运行,则会产生以下异常:

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown ...

如果我关闭 fiddler,程序运行良好,没有任何异常,在我连接的 url 上生成 html。

或者,如果我指定System.setProperty("https.proxyPort", "443");,而不是:System.setProperty("https.proxyPort", "8888");,它会运行并打印出所有 html,无一例外,即使 fiddler 处于打开状态,处于捕获模式,但仍然没有从 fiddler 捕获.

然后,如果我通过 Eclipse 的 jvm 参数设置这些系统属性,例如:-DproxySet=true -DproxyHost=127.0.0.1 -DproxyPort=8888,只要提琴手应用程序在捕获和非捕获模式下运行,就会再次发生相同的异常。如果我关闭 fiddler,程序将运行得很好。

如果我使用:System.setProperty("http.proxyHost", "127.0.0.1"); 而不是:System.setProperty("http.proxyHost", "localhost");,它在 fiddler 应用程序运行时运行良好,无论是上限/非捕获模式,但也没有捕获流量。

有没有人能够使用 fiddler 捕获他们自己的 https 流量,而不是通过网络浏览器,而是通过 java 程序? jvm 参数是什么,你如何设置它来做到这一点?谢谢

【问题讨论】:

标签: java eclipse https fiddler


【解决方案1】:

创建一个包含 Fiddler 证书的密钥库。 将此密钥库与代理设置一起用作 JVM 的信任库。

这是如何做到这一点的:

  • 导出 Fiddler 的根证书

工具 -> Fiddler 选项... -> HTTPS -> 将根证书导出到桌面

  • 使用此证书创建密钥库

以管理员身份打开命令行(否则keytool不起作用)

\bin\keytool.exe -import -file C:\Users\\Desktop\FiddlerRoot.cer -keystore FiddlerKeystore -alias Fiddler

出现提示时输入密码。这应该会创建一个名为 FiddlerKeystore 的文件。

  • 现在启动 JVM,将 Fiddler 作为代理,将此密钥库作为信任库。您将需要这些 vmarg:

-DproxySet=true

-DproxyHost=127.0.0.1

-DproxyPort=8888

-Djavax.net.ssl.trustStore=

-Djavax.net.ssl.trustStorePassword=

在你的 Eclipse 运行配置中使用这些 vmargs,你应该很高兴。

我能够捕获从 JVM 发出的 HTTPS 请求,而此设置没有任何问题。

【讨论】:

  • 我就是这样做的。非常感谢 :) techie-mixture.blogspot.com/2016/07/…
  • 此解决方案也可以使用System.setProperty(<prop>, <value>); 而不是-D<prop>=<value>。谢谢。
  • 使用 Fiddler 5,导出根证书:工具 -> Fiddler 选项... -> HTTPS -> 操作 -> 将根证书导出到桌面
【解决方案2】:

您还可以将 Fiddler 密钥导入 Java 受信任的证书存储区(只要您知道这不安全并且不在任何非开发环境中执行此操作):

  1. 从 Fiddler 中导出 Fiddler 的根证书:

工具 → Fiddler 选项... → HTTPS → 操作 → 将根证书导出到桌面

  1. 启动提升的命令提示符并使用以下命令导入证书。将 jdk1.7.0_79 部分替换为适当的 JDK/JRE 版本。如果您安装了多个 JDK/JRE,则需要针对每个环境执行此操作。
"keytool.exe" -import -noprompt -trustcacerts -alias FiddlerRoot -file c:\work\FiddlerRoot.cer  -keystore "C:\Program Files\Java\jdk1.7.0_79\jre\lib\security\cacerts"  -storepass changeit

我在使用 Google API 客户端和 Fiddler 解密 HTTPS 流量时也遇到了问题。问题是默认情况下,客户端使用它自己的证书存储:

InputStream keyStoreStream = GoogleUtils.class.getResourceAsStream("google.jks");
SecurityUtils.loadKeyStore(certTrustStore, keyStoreStream, "notasecret");

这就是我解决这个问题的方法:

HttpTransport transport = new NetHttpTransport() 
//instead of transport = GoogleNetHttpTransport.newTrustedTransport();

【讨论】:

  • 我正在开发一个 webapp 并使用 jboss / wildfly 18 作为 appserver。我尝试了这个和其他一些类似的选项来让提琴手工作,但还没有运气......“无法找到请求目标的有效认证路径”您的解决方案应该适用于所有 Java 应用程序,对吗?
【解决方案3】:

创建一个包含 fiddler 证书的密钥库并使用它:

java -DproxySet=true -DproxyHost=127.0.0.1 -DproxyPort=8888 -Dhttps.proxyPort=8888 -Dhttps.proxyHost=127.0.0.1 -Djavax.net.ssl.trustStore=<path to FiddlerKeystore> -Djavax.net.ssl.trustStorePassword=<password> -jar test.jar

如果您使用第三方 HTTP 库,则需要设置连接代理。 Apache Commons HttpClient 示例:

HttpClient httpClient = new HttpClient();
httpClient.getHostConfiguration().setProxy("localhost", 8888);

更新:

如果您使用的是 Apache HttpClient 4.5.5 或更新版本,您需要这样做:

HttpHost proxy = new HttpHost("localhost", 8888, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CloseableHttpClient httpclient = HttpClients.custom()
                .setRoutePlanner(routePlanner)
                .build();

【讨论】:

    【解决方案4】:

    我发现我还需要以下 java 命令行选项

    -Dhttps.proxyPort=8888 
    -Dhttps.proxyHost=127.0.0.1
    

    【讨论】:

    • 我也开始使用这些 vmargs,但后来意识到它们是多余的。即,没有它们我可以很好地捕获,并且仅使用这两个,而不是 proxyPort 和 proxyHost args 不起作用。不确定它是否依赖于虚拟机/环境。 --EDIT-- 我是从 Windows 7 上的 Oracle JDK 6 捕获的。