在 Java 客户端中接受服务器的自签名 ssl 证书

新手上路,请多包涵

这看起来像一个标准问题,但我在任何地方都找不到明确的方向。

我有 java 代码试图连接到可能具有自签名(或过期)证书的服务器。代码报告以下错误:

 [HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught
when processing request: sun.security.validator.ValidatorException: PKIX path
building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target

据我了解,我必须使用 keytool 并告诉 java 允许此连接是可以的。

解决此问题的所有说明都假定我完全精通 keytool,例如

为服务器生成私钥并将其导入密钥库

有没有人可以发详细的说明?

我正在运行 unix,所以最好使用 bash 脚本。

不确定它是否重要,但代码在 jboss 中执行。

原文由 Nikita Rybak 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 743
2 个回答

您在这里基本上有两个选择:将自签名证书添加到您的 JVM 信任库或将您的客户端配置为

选项1

从浏览器导出证书并将其导入 JVM 信任库(以建立信任链):

 <JAVA_HOME>\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit

选项 2

禁用证书验证:

 // Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
        public void checkClientTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
            }
        public void checkServerTrusted(
            java.security.cert.X509Certificate[] certs, String authType) {
        }
    }
};

// Install the all-trusting trust manager
try {
    SSLContext sc = SSLContext.getInstance("SSL");
    sc.init(null, trustAllCerts, new java.security.SecureRandom());
    HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
}
// Now you can access an https URL without having the certificate in the truststore
try {
    URL url = new URL("https://hostname/index.html");
} catch (MalformedURLException e) {
}

请注意, 我根本不推荐选项#2 。禁用信任管理器会破坏 SSL 的某些部分,并使您容易受到中间人攻击。首选选项 #1,或者更好的是,让服务器使用由知名 CA 签名的“真实”证书。

原文由 Pascal Thivent 发布,翻译遵循 CC BY-SA 3.0 许可协议

有一个更好的选择来信任所有证书:创建一个 TrustStore 专门信任给定证书并使用它来创建一个 SSLContext 从中获取 SSLSocketFactoryHttpsURLConnection 上设置。这是完整的代码:

 File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));
// Or if the crt-file is packaged into a jar file:
// CertificateFactory.getInstance("X.509").generateCertificate(this.class.getClassLoader().getResourceAsStream("server.crt"));

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());

您也可以直接从文件加载 KeyStore 或从任何受信任的来源检索 X.509 证书。

请注意,使用此代码,将不会使用 cacerts 中的证书。这个特定 HttpsURLConnection 将只信任这个特定的证书。

原文由 Johannes Brodwall 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题