1. Overview
1.概述
In this tutorial, we’ll take a look at common issues we might encounter when issuing SSL requests.
在本教程中,我们将看一下在发出SSL请求时可能遇到的常见问题。
2. Certificate Store Error
2.证书库错误
Whenever a Java application opens an SSL connection with a remote party, it needs to check whether the server is trustworthy or not by validating its certificates. If the root certificate is not contained in the certificate store file, then there will be a security exception:
每当Java应用程序与远程方打开SSL连接时,它需要通过验证其证书来检查该服务器是否值得信赖。如果根证书不包含在证书存储文件中,那么将出现一个安全异常:。
Untrusted: 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
We need to remember that the default location of this file is $JAVA_HOME/lib/security/cacerts.
我们需要记住,这个文件的默认位置是$JAVA_HOME/lib/security/cacerts.。
3. Self-Signed Certificates
3.自签证书
In non-production environments, it is common to find certificates signed by non-trusted issuers, which are known as self-signed certificates.
在非生产环境中,通常会发现由非信任的发行人签署的证书,这被称为自签名证书。
We can find some examples of untrusted certificates under https://wrong.host.badssl.com/ or https://self-signed.badssl.com/. Opening both URLs in any browser will result in a security exception. We can check them out and see the differences in the certificates.
我们可以在https://wrong.host.badssl.com/ 或 https://self-signed.badssl.com/ 下找到一些不受信任的证书的例子。在任何浏览器中打开这两个URL都会导致安全异常。我们可以检查一下,看看证书的差异。
After opening https://self-signed.badssl.com/, we can see the browser returns a “Cert Authority Invalid” error, as the certificate has been issued by an authority that is unknown to the browser:
打开https://self-signed.badssl.com/,我们可以看到浏览器返回一个“Cert Authority Invalid”错误,因为该证书是由一个浏览器未知的机构颁发的。
On the other hand, opening https://wrong.host.badssl.com/ results in a “Cert Common Name Invalid” error, another kind of error that indicates the certificate has been issued for a different hostname than the provided one:
另一方面,打开https://wrong.host.badssl.com/,会出现“Cert Common Name Invalid”错误,这是另一种错误,表明证书是为一个与所提供的主机名不同的主机名签发的。
The same will occur for an application running inside the JDK/JRE. These security exceptions will prevent us from opening an SSL connection to those untrusted parties.
在JDK/JRE内运行的应用程序也会出现同样的情况。这些安全异常将阻止我们向那些不受信任的各方打开SSL连接。。
4. Managing the Certificate Store to Trust Our Certificates
4.管理证书库以信任我们的证书
Lucky us, the JDK/JRE provides a tool to interact with the certificate store to administer its content. This tool is the Keytool and can be found in $JAVA_HOME/bin/keytool.
幸运的是,JDK/JRE 提供了一个与证书库互动的工具,以便管理其内容。这个工具就是Keytool,可以在$JAVA_HOME/bin/keytool找到。
Important Note: keytool requires a password to interact with it. The default password is “changeit”.
重要提示。keytool需要一个密码来与之互动。默认密码是“changeit”。。
4.1. List Certificates
4.1.列表中的证书
To get a list of all the certificates registered in the JVM’s certificate store, we need to issue the following command:
为了获得在JVM的证书库中注册的所有证书的列表,我们需要发出以下命令。
keytool -list -keystore $JAVA_HOME/lib/security/cacerts
This will return a list with all the entries, like:
这将返回一个包含所有条目的列表,如。
Your keystore contains 227 entries
Alias name: accvraiz1
Creation date: Apr 14, 2021
Entry type: trustedCertEntry
Owner: C=ES, O=ACCV, OU=PKIACCV, CN=ACCVRAIZ1
Issuer: C=ES, O=ACCV, OU=PKIACCV, CN=ACCVRAIZ1
....
4.2. Add Certificates
4.2.添加证书
To manually add a certificate into that list, so it gets validated whenever we issue an SSL request, we need to execute the following command:
要手动将证书添加到该列表中,以便在我们发出SSL请求时得到验证,我们需要执行以下命令。
keytool -import -trustcacerts -file [certificate-file] -alias [alias] -keystore $JAVA_HOME/lib/security/cacerts
For instance:
比如说。
keytool -import -alias ss-badssl.com -keystore $JAVA_HOME/lib/security/cacerts -file ss-badssl.pem
4.3. Custom Certificate Store Path
4.3.自定义证书库路径
If nothing of the above works, it might be the case our Java application is using a different certificate store. To make sure of it, we can specify the certificate store to use whenever we run your Java application:
如果上述方法都不奏效,可能是我们的Java应用程序使用了不同的证书库。为了确定这一点,我们可以在运行你的Java应用程序时指定要使用的证书库。
java -Djavax.net.ssl.trustStore=CustomTrustStorePath ...
That way, we make sure it’s using the certificate store we previously edited. If that doesn’t help, we can also debug SSL connections by applying the VM option:
这样,我们就能确保它在使用我们之前编辑的证书存储。如果这还没有帮助,我们还可以通过应用虚拟机选项来调试SSL连接。
-Djavax.net.debug=all
5. Automation Script
5.自动化脚本
Wrapping up, we can create a simple but handy script to automate the whole process:
总结一下,我们可以创建一个简单但方便的脚本,使整个过程自动化。
#!/bin/sh
# cacerts.sh
/usr/bin/openssl s_client -showcerts -connect $1:443 </dev/null 2>/dev/null | /usr/bin/openssl x509 -outform PEM > /tmp/$1.pem
$JAVA_HOME/bin/keytool -import -trustcacerts -file /tmp/$1.pem -alias $1 -keystore $JAVA_HOME/lib/security/cacerts
rm /tmp/$1.pem
In the script, we can see the first part opens an SSL connection to the DNS passed as the first argument and requests it to show the certificates. After that, the certificate information is piped through openssl to digest it and store it as a PEM file.
在该脚本中,我们可以看到第一部分打开一个SSL连接到作为第一个参数传递的DNS,并要求它显示证书。之后,证书信息通过openssl管道被消化并存储为一个PEM文件。
Finally, this PEM file is the one we’ll use by instructing the keytool to import the certificate into the cacerts file with the DNS as the alias.
最后,通过指示keytool将证书导入以DNS为别名的cacerts文件,这个PEM文件就是我们要使用的。
For instance, we can try adding the certificate for https://self-signed.badssl.com:
例如,我们可以尝试添加 https://self-signed.badssl.com 的证书。
cacerts.sh self-signed.badssl.com
And after running it, we can check our cacerts file now contains the certificate:
运行后,我们可以检查我们的cacerts文件现在是否包含证书。
keytool -list -keystore $JAVA_HOME/lib/security/cacerts
Finally, we’ll see the new certificate is there:
最后,我们会看到新的证书在那里。
#5: ObjectId: 2.5.29.32 Criticality=false
CertificatePolicies [
[CertificatePolicyId: [2.5.29.32.0]
Alias name: self-signed.badssl.com
Creation date: Oct 22, 2021
Entry type: trustedCertEntry
Owner: CN=*.badssl.com, O=BadSSL, L=San Francisco, ST=California, C=US
Issuer: CN=*.badssl.com, O=BadSSL, L=San Francisco, ST=California, C=US
Serial number: c9c0f0107cc53eb0
Valid from: Mon Oct 11 22:03:54 CEST 2021 until: Wed Oct 11 22:03:54 CEST 2023
Certificate fingerprints:
....
6. Manually Adding a Certificate
6.手动添加证书
We can also use our browser to extract the certificate and add it through keytool if, for any reason, we don’t want to use openssl.
如果出于任何原因,我们不想使用openssl,我们也可以使用浏览器提取证书并通过keytool添加。
In Chromium-based browsers, we open the website like https://self-signed.badssl.com/ and open the developer tools (F12 for Windows and Linux). Let’s then click on the Security tab and finally on “View Certificate”. The certificate information will show up:
在基于Chromium的浏览器中,我们打开网站,如https://self-signed.badssl.com/,并打开开发者工具(Windows和Linux的F12)。然后让我们点击安全标签,最后点击 “查看证书”。证书信息将显示出来。
Let’s go to the “Details” tab, click on the “Export” button and save it. That’s our PEM file:
让我们进入 “细节 “选项卡,点击 “导出 “按钮并保存它。这就是我们的PEM文件。
Finally, we import it using keytool:
最后,我们用keytool导入它。
$JAVA_HOME/bin/keytool -import -trustcacerts -file CERTIFICATEFILE -alias ALIAS -keystore $JAVA_HOME/lib/security/cacerts
7. Conclusion
7.结语
In this article, we’ve seen how to add a self-signed certificate to our JDK/JRE certificate store. Now, our Java applications can trust the server-side whenever they open an SSL connection to sites containing these certificates.
在这篇文章中,我们已经看到了如何将自签名证书添加到JDK/JRE证书存储中。现在,我们的Java应用程序只要打开与包含这些证书的网站的SSL连接,就可以信任服务器端。