使用给定的 p12 证书连接到 https 站点

2022-09-01 03:11:39

服务器端给了我一个证书文件,我已经点击并安装在我的机器上,然后我可以通过浏览器访问该网站。现在,他们希望我使用给定的证书抓取他们的网站。我被困在它的第一阶段,试图从.该网站没有登录名。它只检查您是否拥有证书。.p12HTTPSinputStreamhttpsURLConnection

到目前为止,我所做的是使用Firefox以文件格式导出证书。然后我使用keytool命令将其(文件,而不是)导入java密钥库。然后在代码中:.crt.crt.p12

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
File ksFile = new File(keystorePath);
in = new FileInputStream(ksFile);
ks.load(in, "changeit".toCharArray());
X509Certificate cert = (X509Certificate) ks.getCertificate(certificateAlias);

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

HttpsURLConnection con = (HttpsURLConnection) (new URL(urlString)).openConnection();
con.connect();
con.getInputStream();
con.disconnect();

将给我403错误禁止访问。我搜索了其他相关主题,实际上比阅读它们之前更加困惑。非常感谢答案。getInputStream()

其他详细信息:

  • 我只是刚刚实例化了证书,并没有让程序知道任何类型的密钥(私有,公共等)。因此,我认为我必须向服务器提供这些密钥,让它知道我实际上持有证书。我完全不知道如何做到这一点,无论是逻辑还是语法方面。
  • 我已经尝试了keytool命令将.p12 cert文件导入密钥库,但不知何故,keytool无法识别-pkcs12选项。关于如何直接使用此.p12证书的任何想法也都很棒。
  • trustAllCert是TrustMangers的一个单元素数组,它不验证任何东西(全部信任)。我不知道我是否应该继续使用它。事实上,现在我实际上只有一个证书可以信任。在这种情况下,编写信任管理器的正确方法是什么?
  • 我无法控制服务器端。我得到的只是访问他们网站的URL,这是在HTTPS协议下,以及一个.p12证书。该网站没有登录名。如果安装了证书,我可以进去。

答案 1

如果要尝试对 SSL 配置进行编码,可以使用提供给您的 P12 文件,而不必将其转换为 JKS。此外,还需要使用 P12 中的私钥,而不仅仅是复制到 JKS 中的证书。不确定这是否能直接满足您的需求,但这可能会让您走上正确的道路:

        KeyStore clientStore = KeyStore.getInstance("PKCS12");
        clientStore.load(new FileInputStream("test.p12"), "testPass".toCharArray());

        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(clientStore, "testPass".toCharArray());
        KeyManager[] kms = kmf.getKeyManagers();

        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream("cacerts"), "changeit".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
        TrustManager[] tms = tmf.getTrustManagers();

        SSLContext sslContext = null;
        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kms, tms, new SecureRandom());

        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        URL url = new URL("https://www.testurl.com");

        HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection();

以这种方式配置信任库是可选的。您可以使用 P12 链中的所有证书创建一个 JKS,或者只是确保它们位于 JRE 的 cacerts 文件中。至于keytool,作为参考,您可以在P12上运行keytool命令(指定-storetype pkcs12),但不能将P12导入到JKS中。您也不能使用 keytool 命令仅从 P12 导出密钥。

我目前没有设置服务器来测试此代码,因此请试一试,看看是否仍然收到403错误。


答案 2

将此添加为答案,因为我需要更多的空间来编写。

首先,一个问题:证书是否由受信任的颁发机构(如威瑞信)签名?如果不是,则信任库应具有 CA 证书(通常是 .pem 文件),这使得 p12 证书“有效”。默认的java信任存储包含来自大公司的大多数(如果不是全部)CA证书,例如Verisign和Thawte。

此外,还可以测试应用以连接到安全服务器,而无需对 SSL 配置进行编码,但使用一些命令行参数,例如:

java -Djavax.net.ssl.keyStore=[path_to_p12_cert] \
 -Djavax.net.ssl.keyStorePassword=[p12_password] \
 -Djavax.net.ssl.keyStoreType=PKCS12 \
 -Djavax.net.ssl.trustStore=[path_to_trust_store_with_CA_certificates] \
 -Djavax.net.ssl.trustStorePassword=[trust_store_password] \
 [MainClass]

然后你的代码变得只是

HttpsURLConnection con = (HttpsURLConnection) (new URL(urlString)).openConnection();
con.connect();
con.getInputStream();
con.disconnect();

如果您觉得受虐狂,JSSE参考指南非常有趣。