猿问

如何在特定连接上使用不同的证书?

如何在特定连接上使用不同的证书?

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

以下是基本代码:

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

如果没有对自签名证书进行任何额外的处理,它就会死在con.getOutputStream()上,但有以下例外:

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接受这个自签名证书,这是应用程序中的一个地方,而不是其他地方。

我知道我可以将证书导入到JRE的证书颁发机构存储中,这将允许Java接受它。如果我能帮忙的话,这不是我想要采取的一种方法;在我们所有客户的机器上使用他们可能不使用的模块,这似乎很有侵略性;它会影响使用相同JRE的所有其他Java应用程序,即使其他Java应用程序访问这个站点的几率为零,我也不喜欢这样做。这也不是一个简单的操作:在UNIX上,我必须获得访问权才能以这种方式修改JRE。

我还看到我可以创建一个TrustManager实例来执行一些自定义检查。看起来,我甚至可以创建一个TrustManager,它在所有情况下都委托给真正的TrustManager,但这个证书除外。但看起来TrustManager是在全球范围内安装的,我想这会影响到我们应用程序中的所有其他连接,这对我来说也不太合适。

设置Java应用程序以接受自签名证书的首选、标准或最佳方法是什么?我能完成我在上面想到的所有目标吗?还是我要妥协?是否有涉及文件、目录和配置设置以及小到无代码的选项?


眼眸繁星
浏览 548回答 3
3回答

扬帆大鱼

创建一个SSLSocket亲自出厂,并将其设置在HttpsURLConnection在连接之前。...HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();conn.setSSLSocketFactory(sslFactory);conn.setMethod("POST");...你会想要创建一个SSLSocketFactory把它留着。下面是如何初始化它的草图:/* 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();如果您需要帮助创建密钥存储,请评论。下面是一个加载密钥存储的示例:KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());keyStore.load(trustStore, trustStorePassword);trustStore.close();若要使用PEM格式证书创建密钥存储,可以使用CertificateFactory,或者直接用keytool来自JDK(KeyTool)不会为一个“关键条目”工作,但对于一个“可信条目”来说很好)。keytool -import -file selfsigned.pem -alias server -keystore server.jks
随时随地看视频慕课网APP

相关分类

Java
我要回答