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

发布于 2024-11-28 18:48:13 字数 1474 浏览 0 评论 0原文

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

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

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();

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

其他详细信息:

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

The server side gave me a .p12 certificate file which I've clicked and installed on my machine and then I can access the HTTPS site through browser. Now they want me to crawl their site with the certificate given. I'm stuck at the very first stage of it, trying to get the inputStream from the httpsURLConnection. The site has no login. It only checks if you have the certificate or not.

What I've done so far was to use Firefox to export out the certificate in a .crt file format. Then I used the keytool command to import it (the .crt file, not the .p12) into java keystore. Then in the code:

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();

The getInputStream() will give me 403 error forbidden access. I've searched through other related topics and are actually deeply more confused than before reading them. Would greatly appreciate answers.

Additional Details:

  • I've only just instantiated the certificate, and have not let the program knows any sort of keys (private, public, etc.). So what I believe I must present these keys to the server, letting it know I'm actually holding the certificate. I have absolutely no idea how to do this, both logic and syntax wise.
  • I've tried keytool command to import the .p12 cert file into the keystore but somehow, the -pkcs12 option is not recognized by the keytool. Any idea on how to directly use this .p12 cert would be great as well.
  • trustAllCert is a one element array of TrustMangers which does not validate anything (trust all). I don't know if I should continue to use this. In fact, now I actually have a single cert to trust. What is the proper way to write a trustManger in this case?
  • I have no control over the server side. All I was given are the URL to access their site, which is under HTTPS protocol, and a .p12 certificate. The site has no login. If the certificate is installed, I can go in.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

黑色毁心梦 2024-12-05 18:48:13

如果您想尝试对 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();

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

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

If you want to attempt to code up the SSL configuration, you could use the P12 file given to you without having to convert it into a JKS. Also, you will need to use the private key in the P12, and not just the certificates that you copied into the JKS. Not sure if this will suit your needs directly, but this may put you on the right path:

        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();

Configuring the trustStore this way is optional. You could create a JKS with all of the certificates in the chain of your P12, or just make sure they are in your JRE's cacerts file. As for keytool, for reference, you can run keytool commands on a P12 (specify -storetype pkcs12), but cannot import a P12 into a JKS. You also cannot export just a key from a P12 with the keytool command.

I have no servers setup at the moment to test out this code, so give it a shot and see if you still receive the 403 error.

一绘本一梦想 2024-12-05 18:48:13

这对我有用:

   KeyStore keyStore  = KeyStore.getInstance("PKCS12");
    FileInputStream instream = new FileInputStream(new File("client-p12-keystore.p12"));
    try {
        keyStore.load(instream, "password".toCharArray());
    } finally {
        instream.close();
    }

    // Trust own CA and all self-signed certs
    SSLContext sslcontext = SSLContexts.custom()
        .loadKeyMaterial(keyStore, "password".toCharArray())
        //.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
        .build();
    // Allow TLSv1 protocol only
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    CloseableHttpClient httpclient = HttpClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLSocketFactory(sslsf)
        .build();
    try {

        HttpGet httpget = new HttpGet("https://localhost:8443/secure/index");

        System.out.println("executing request" + httpget.getRequestLine());

        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
            }
            EntityUtils.consume(entity);
        } finally {
            response.close();
        }
    } finally {
        httpclient.close();
    }
}

This is what worked for me:

   KeyStore keyStore  = KeyStore.getInstance("PKCS12");
    FileInputStream instream = new FileInputStream(new File("client-p12-keystore.p12"));
    try {
        keyStore.load(instream, "password".toCharArray());
    } finally {
        instream.close();
    }

    // Trust own CA and all self-signed certs
    SSLContext sslcontext = SSLContexts.custom()
        .loadKeyMaterial(keyStore, "password".toCharArray())
        //.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
        .build();
    // Allow TLSv1 protocol only
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    CloseableHttpClient httpclient = HttpClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .setSSLSocketFactory(sslsf)
        .build();
    try {

        HttpGet httpget = new HttpGet("https://localhost:8443/secure/index");

        System.out.println("executing request" + httpget.getRequestLine());

        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
            }
            EntityUtils.consume(entity);
        } finally {
            response.close();
        }
    } finally {
        httpclient.close();
    }
}
一杆小烟枪 2024-12-05 18:48:13

添加此作为答案,因为我需要更多空间来书写。

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

此外,您可以测试您的应用程序以连接到安全服务器,而无需对 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 参考指南 非常有趣。

Adding this as an answer as I need more space to write.

First, a question: Is the certificate signed by a trusted authority such as Verisign? If it's not, the truststore should have the CA Certificate (usually a .pem file) which makes the p12 cert 'valid'. The default java trust store contains most (if not all) of the CA certificates from the big companies, such as Verisign and Thawte.

Also, you can test your app to connect to the secure server without coding the SSL configuration, but with some command line parameters, for example:

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]

and then your code becomes just

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

If you feel masochistic, the JSSE ref guide is great fun.

绅刃 2024-12-05 18:48:13

如果您使用 Spring,可以通过 RestTemplate 访问它:

public RestTemplate restTemplate() throws Exception {
    KeyStore clientStore = KeyStore.getInstance("PKCS12");
    InputStream resource = this.getClass().getClassLoader().getResourceAsStream("path_to_certificate.p12");
    clientStore.load(resource, "p12_password".toCharArray());

    SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
    sslContextBuilder.setProtocol("TLS");
    sslContextBuilder.loadKeyMaterial(clientStore, "p12_password".toCharArray());
    sslContextBuilder.loadTrustMaterial(new TrustSelfSignedStrategy());

    SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build());
    CloseableHttpClient httpClient = HttpClients.custom()
        .setSSLSocketFactory(sslConnectionSocketFactory)
        .build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
    return new RestTemplate(requestFactory);
}

In case you are using Spring, it could be reached by RestTemplate:

public RestTemplate restTemplate() throws Exception {
    KeyStore clientStore = KeyStore.getInstance("PKCS12");
    InputStream resource = this.getClass().getClassLoader().getResourceAsStream("path_to_certificate.p12");
    clientStore.load(resource, "p12_password".toCharArray());

    SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
    sslContextBuilder.setProtocol("TLS");
    sslContextBuilder.loadKeyMaterial(clientStore, "p12_password".toCharArray());
    sslContextBuilder.loadTrustMaterial(new TrustSelfSignedStrategy());

    SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContextBuilder.build());
    CloseableHttpClient httpClient = HttpClients.custom()
        .setSSLSocketFactory(sslConnectionSocketFactory)
        .build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
    return new RestTemplate(requestFactory);
}
橘寄 2024-12-05 18:48:13

简单的 keytool 命令会将您的 .p12 密钥库导出到 .jks 密钥库:

keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore keystore.jks

Simple keytool command would export your .p12 keystore into .jks keystore:

keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore keystore.jks

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文