Java HTTPS 编程梳理
HTTPS 通信流程
流程(仅验证服务端方式)
核心流程概述:
- 前提:服务端持有私钥和公钥;
- 客户端获取服务端的公钥(实际上被包在证书里面),并通过本地信任链来验证服务端公钥合法性;
- 客户端生成随机字符串作为密码,并将其用公钥加密,发送密文给服务端;
- 服务端收到密码密文,使用私钥对其进行解密,得到密码的明文;
- 后续通信服务端和客户端共同使用该密码,发送方采用此密码对数据进行对称加密,接收方使用该密码对数据进行对称解密;
- 总结:密码加密使用非对称加密,数据加密使用对称加密。
详细的HTTPS握手流程参考:RFC 5246 7.4. Handshake Protocol
概念介绍
- 秘钥对keypair:包含服务方私钥和公钥(private-key、public-key)
- 证书certificate:包含服务方公钥、过期时间、服务方名称、证书颁发机构名称等
- 证书签发申请certificate sign req:根据私钥生成的csr文件
- 数字签名certificate sign:认证机构CA给csr申请文件进行签名,得到证书cert文件
- 自签名certificate selfsign:使用自己的ca文件对自己进行签名,得到证书cert文件;顶级认证机构将使用自签名根证书来签发子证书
证书签发流程示例:
# 生成keypair
openssl genrsa -des3 -out private.key 1024
# 生成申请,本质使用public-key的信息
openssl req -new -days 365 -key private.key -out req.csr
# 自签名
openssl ca -selfsign -in req.csr -out root.ca
# 签发证书
openssl ca -in newreq.csr -cert root.ca -keyfile private.key -out user.ca
认证机构签名过程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8IIXrog5-1605498407795)(sign.png)]
关键问题
客户端如何验证服务端合法?
当使用浏览器访问时,客户端会收到服务端发送的证书server.ca(流程参考RFC 7.4.2. Server Certificate),server.ca中包含服务方的公钥server.publickey和签名sign,签名sign是认证机构使用其私钥ca.privatekey对server.publickey摘要进行加密得到的,客户端浏览器内置了认证机构的公钥ca.publickey,客户端使用ca.publickey对签名sign进行解密,得到hash1值,客户端对server.publickey进行摘要得到hash2值,对比hash1和hash2若相同则判断合法。
服务端如何验证客户端合法?
使用相反的方向,客户端持有一个client.keypair,给服务端发送client.ca证书,从而由服务端验证客户端是否合法。
Java keystore truststore 机制
- keystore:用于存储秘钥对keypair的文件(可以包含多个keypair),keypair包含了服务端私钥与公钥。
- truststore:用于存储证书certificate的文件(可以包含多个certificate),certificate包含了受信任的证书,以验证服务端公钥是否合法。
生成秘钥对并放入keystore:
keytool -genkeypair -keystore hugegraph.keystore -alias ke