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

2022-01-30 00:00:00 https ssl java keytool

这似乎是一个标准问题,但我在任何地方都找不到明确的方向.

It looks like a standard question, but I couldn't find clear directions anywhere.

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

I have java code trying to connect to a server with probably self-signed (or expired) certificate. The code reports the following error :

[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 允许这个连接是可以的.

As I understand it, I have to use keytool and tell java that it's OK to allow this connection.

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

All instructions to fix this problem assume I'm fully proficient with keytool, such as

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

generate private key for server and import it into keystore

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

Is there anybody who could post detailed instructions?

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

I'm running unix, so bash script would be best.

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

Not sure if it's important, but code executed in jboss.

推荐答案

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

You have basically two options here: add the self-signed certificate to your JVM truststore or configure your client to

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

Export the certificate from your browser and import it in your JVM truststore (to establish a chain of trust):

<JAVA_HOME>inkeytool -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 签名的真实"证书.

Note that I do not recommend the Option #2 at all. Disabling the trust manager defeats some parts of SSL and makes you vulnerable to man in the middle attacks. Prefer Option #1 or, even better, have the server use a "real" certificate signed by a well known CA.

相关文章