如何在特定连接上使用不同的证书? [英] How can I use different certificates on specific connections?

查看:104
本文介绍了如何在特定连接上使用不同的证书?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在添加到我们的大型Java应用程序的模块必须与另一家公司的SSL安全网站进行交谈。问题是该站点使用自签名证书。我有一份证书副本,以验证我没有遇到中间人攻击,我需要将此证书合并到我们的代码中,以便与服务器的连接成功。

A module I'm adding to our large Java application has to converse with another company's SSL-secured website. The problem is that the site uses a self-signed certificate. I have a copy of the certificate to verify that I'm not encountering a man-in-the-middle attack, and I need to incorporate this certificate into our code in such a way that the connection to the server will be successful.

以下是基本代码:

void sendRequest(String dataPacket) {
  String urlStr = "https://host.example.com/";
  URL url = new URL(urlStr);
  HttpURLConnection conn = (HttpURLConnection)url.openConnection();
  conn.setMethod("POST");
  conn.setRequestProperty("Content-Length", data.length());
  conn.setDoOutput(true);
  OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
  o.write(data);
  o.flush();
}

如果没有为自签名证书进行任何额外处理,这将死于conn.getOutputStream(),但有以下异常:

Without any additional handling in place for the self-signed certificate, this dies at conn.getOutputStream() with the following exception:

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
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

理想情况下,我的代码需要教Java接受这是一个自签名证书,适用于应用程序中的这一点,而不是其他任何地方。

Ideally, my code needs to teach Java to accept this one self-signed certificate, for this one spot in the application, and nowhere else.

我知道我可以将证书导入JRE的证书颁发机构商店,这将允许Java接受它。如果我能提供帮助,那不是我想采取的方法;对于他们可能不使用的一个模块,我们所有客户的机器上看起来非常具有侵入性;它会影响使用相同JRE的所有其他Java应用程序,我不喜欢它,即使访问此站点的任何其他Java应用程序的几率为零。这也不是一个简单的操作:在UNIX上我必须获得以这种方式修改JRE的访问权限。

I know that I can import the certificate into the JRE's certificate authority store, and that will allow Java to accept it. That's not an approach I want to take if I can help; it seems very invasive to do on all of our customer's machines for one module they may not use; it would affect all other Java applications using the same JRE, and I don't like that even though the odds of any other Java application ever accessing this site are nil. It's also not a trivial operation: on UNIX I have to obtain access rights to modify the JRE in this way.

我还看到我可以创建一个TrustManager实例做一些自定义检查。看起来我甚至可以创建一个TrustManager,在除了这个证书之外的所有实例中委托给真正的TrustManager。但看起来全局安装了TrustManager,我认为会影响我们应用程序的所有其他连接,这对我来说也不是很合适。

I've also seen that I can create a TrustManager instance that does some custom checking. It looks like I might even be able to create a TrustManager that delegates to the real TrustManager in all instances except this one certificate. But it looks like that TrustManager gets installed globally, and I presume would affect all other connections from our application, and that doesn't smell quite right to me, either.

设置Java应用程序以接受自签名证书的首选,标准或最佳方法是什么?我可以完成上面提到的所有目标,还是我必须妥协?是否有涉及文件和目录及配置设置的选项,以及几乎没有代码?

What is the preferred, standard, or best way to set up a Java application to accept a self-signed certificate? Can I accomplish all of the goals I have in mind above, or am I going to have to compromise? Is there an option involving files and directories and configuration settings, and little-to-no code?

推荐答案

创建一个 SSLSocket 自己出厂,并在连接前将其设置在 HttpsURLConnection 上。

Create an SSLSocket factory yourself, and set it on the HttpsURLConnection before connecting.

...
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslFactory);
conn.setMethod("POST");
...

您需要创建一个 SSLSocketFactory 并保持它。下面是如何初始化它的草图:

You'll want to create one SSLSocketFactory and keep it around. Here's a sketch of how to initialize it:

/* Load the keyStore that includes self-signed cert as a "trusted" entry. */
KeyStore keyStore = ... 
TrustManagerFactory tmf = 
  TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);
sslFactory = ctx.getSocketFactory();

如果您在创建密钥库时需要帮助,请发表评论。

If you need help creating the key store, please comment.

以下是加载密钥库的示例:

Here's an example of loading the key store:

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(trustStore, trustStorePassword);
trustStore.close();

要使用PEM格式证书创建密钥存储区,您可以使用<$ c编写自己的代码$ c> CertificateFactory ,或者只从JDK导入 keytool (keytool 不会为密钥条目,但对于受信任的条目是好的。)

To create the key store with a PEM format certificate, you can write your own code using CertificateFactory, or just import it with keytool from the JDK (keytool won't work for a "key entry", but is just fine for a "trusted entry").

keytool -import -file selfsigned.pem -alias server -keystore server.jks

这篇关于如何在特定连接上使用不同的证书?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆