Java的HTTP客户端如何验证服务器的CA证书?

3

我正在尝试理解SSL并阅读不同的文章。所有的文章都有像这样的图片(图片来源):

enter image description here

有很多例子,但我想了解第三步。如果我使用浏览器,那是可以理解的。浏览器本身具有验证机制。但是如果我使用我的Java客户端呢?例如,我有一个应用程序,向https://www.google.com/search?q=weather发出请求。我如何验证Google的证书?我需要这样做吗?我应该获取这个证书并将其添加到信任存储中吗?也许我只应该将非公共证书添加到信任存储中?

有人能解释一下Java HTTP客户端进行验证的一系列步骤吗?(您可以使用任何Java HTTP客户端进行解释)


Java 做到了类似于网络浏览器的功能:两者都有可信 CA 的列表。同时,它们都会检查服务器证书是否在有效期内,并且是否被可信 CA 签署。 - Thomas Kläger
我明白了,但是Java是如何做到的呢?我知道Java会将一些证书存储在其存储中。但如果不是Google而是公共API呢?例如,我一年前在我的计算机上安装了Java。昨天开发了新的API并颁发了他们的证书。Java如何获取此证书进行验证? - Pavel Petrashov
无论证书何时颁发,只要证书颁发机构(或其祖先颁发机构之一)在受信任的CA列表中即可。例如,在stackoverflow.com使用的证书是由“R3,Let's Encrypt,US”于2022年1月4日签署的。 “R3”证书本身是由“XSRG Root X1,…”于2020年9月4日签署的。只要“R3”证书或创建于2015年的“XSRG Root X1”之一在CA列表中,您的Java应用程序(自2016年起)就可以验证“stackoverflow.com”证书。 - Thomas Kläger
2个回答

4
在第二步中,服务器提供它的服务器证书。这个证书由官方认证机构(CA、根CA)如Baltimore Cypertrust、Entrust、DigiCert、Verisign等颁发和签名,或者由中间认证机构(ICA)颁发和签名的ICA证书。
在CA/ICA颁发证书之前,它会验证请求者(也称为主体)的身份,确保该人或公司是真正的本人,并且拥有应颁发证书的域名。
这建立了所谓的信任链,从服务器证书向后追溯到可信任的机构。
在第三步中,验证第2步的证书是否导向已知的CA/ICA。如果是,则接受证书作为可信任的。为此,Java提供了一个存储所有有效根和中间证书的证书库。
要列出其内容,请打开命令窗口,切换到文件夹 .../jre1.x.y_zzz/lib/security/ 并输入命令 ../../bin/keytool.exe -keystore cacerts -list。可以通过按回车键跳过密码输入的问题。然后您将获得存储在默认存储中的所有证书的列表。
dude@cs04n4 /cygdrive/c/Program Files/Java/jre1.8.0_301/lib/security
$ ../../bin/keytool.exe -keystore cacerts -list
Keystore-Kennwort eingeben:

*****************  WARNING WARNING WARNING  *****************
* Die Integrität der Informationen, die in Ihrem Keystore gespeichert sind, *
* wurde NICHT geprüft. Um die Integrität zu prüfen, *
* müssen Sie Ihr Keystore-Kennwort angeben.                  *
*****************  WARNING WARNING WARNING  *****************

Keystore-Typ: JKS
Keystore-Provider: SUN

Keystore enth▒lt 92 Eintr▒ge

sslrooteccca [jdk], 31.07.2020, trustedCertEntry,
Zertifikat-Fingerprint (SHA-256): 34:17:BB:06:CC:60:07:DA:1B:96:1C:92:0B:8A:B4:CE:3F:AD:82:0E:4A:A3:0B:9A:CB:C4:A7:4E:BD:CE:BC:65
digicertassuredidg3 [jdk], 25.08.2016, trustedCertEntry,
Zertifikat-Fingerprint (SHA-256): 7E:37:CB:8B:4C:47:09:0C:AB:36:55:1B:A6:F4:5D:B8:40:68:0F:BA:16:6A:95:2D:B1:00:71:7F:43:05:3F:C2
verisignuniversalrootca [jdk], 25.08.2016, trustedCertEntry,
Zertifikat-Fingerprint (SHA-256): 23:99:56:11:27:A5:71:25:DE:8C:EF:EA:61:0D:DF:2F:A0:78:B5:C8:06:7F:4E:82:82:90:BF:B8:60:E8:4B:3C
digicerttrustedrootg4 [jdk], 25.08.2016, trustedCertEntry,
Zertifikat-Fingerprint (SHA-256): 55:2F:7B:DC:F1:A7:AF:9E:6C:E6:72:01:7F:4F:12:AB:F7:72:40:C7:8E:76:1A:C2:03:D1:D9:D2:0A:C8:99:88
...
ttelesecglobalrootclass2ca [jdk], 25.08.2016, trustedCertEntry,
Zertifikat-Fingerprint (SHA-256): 91:E2:F5:78:8D:58:10:EB:A7:BA:58:73:7D:E1:54:8A:8E:CA:CD:01:45:98:BC:0B:14:3E:04:1B:17:05:25:52
addtrustqualifiedca [jdk], 25.08.2016, trustedCertEntry,
Zertifikat-Fingerprint (SHA-256): 80:95:21:08:05:DB:4B:BC:35:5E:44:28:D8:FD:6E:C2:CD:E3:AB:5F:B9:7A:99:42:98:8E:B8:F4:DC:D0:60:16
digicertglobalrootca [jdk], 25.08.2016, trustedCertEntry,
Zertifikat-Fingerprint (SHA-256): 43:48:A0:E9:44:4C:78:CB:26:5E:05:8D:5E:89:44:B4:D8:4F:96:62:BD:26:DB:25:7F:89:34:A4:43:C7:01:61

dude@cs04n4 /cygdrive/c/Program Files/Java/jre1.8.0_301/lib/security

设置SSL连接时,您可以选择使用默认信任存储区或使用自己的信任存储区。如果您决定使用自己的信任存储区,则必须创建并导入您信任的服务器/根证书。


Java提供了一个存储所有认证机构的有效根和中间证书的库。我该如何查看所有这些证书和机构? - Pavel Petrashov

1
整个公钥基础架构 (PKI) 是必要的,以确定发送数据的人是否真的是那个人,而不是中间人。为此,应该有一些第三方(你信任的人)来检查网站所有者并为其创建和签署证书。你可以检查证书是否有效,因为它是由 CA 签名的,而你信任该 CA。
如何设置信任的对象?你需要在某个地方存储一个列表。在 Java 中,受信任机构及其公钥的存储位置位于文件 $JAVA_HOME/lib/security/cacerts 中。该文件最初来自 Java 安装程序,其中包含具有证书的主要 CA(是的,它们会在某个时候过期)。该文件可以使用随Java一起提供的 keytool 实用程序进行修改(可以添加或删除 CA 证书)。
现在变得有点复杂了,因为 CA 有证书级别:有一个根证书,用于签署中间证书,然后用于签署网站所有者的证书。当你的 Java 代码需要使用 TLS/SSL 进行通信时,它需要:
  1. 下载网站证书
  2. 检查它是否由受信任的CA签名

但是,当网站的证书由中间证书签名时,我们并不总是将其存储在中。通常只有根证书会被存储。在这种情况下,有两个选择 - 要么将中间证书添加到中(不好的解决方案),要么网站所有者需要设置一个包含他的证书、签署他的证书、签署该证书的证书等的证书链,直到达到根。在这种设置中,只要您可以检查此链中的任何证书 - 您就会信任该网站。


1
我不建议将证书导入Java cacerts文件中。这些更改会在每次Java更新时丢失,并导致令人惊讶的故障。在大多数情况下,最好使用所需证书设置自己的信任存储库。这样更容易管理,并且更加清晰易懂。 - Stefan D.
1
请注意,自1990年代以来的所有SSL/TLS标准都要求服务器发送完整的证书链(可选择省略根证书)--这是您的第二选择--尽管许多服务器操作员会搞砸这一点;每天或两天就会在此或其他堆栈上出现问题。还有第三种选择:今天大多数CA都提供AuthorityInfoAccess扩展,指定可以获取中间证书的位置;浏览器会自动执行,而Java默认情况下不会执行,但可以设置为执行。 - dave_thompson_085

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接