简介
Java 和 HTTP 的那些事(四) HTTPS 和 证书
计算机安全相关汇总
对称加密的问题
- 密钥如何传输?
- 密钥如何存储?对于浏览器的网页来说,都是明文的。
当然,两个问题其实是一个问题,解决了密钥传输问题,就可以在建立连接之后获取密钥,只存在内存中。
2018.04.18 新增
从中可以看到,有一条线:
- 加密由加密算法 + 密钥组成,加密算法公开,于是密钥分发成了关键
- 密钥的定向分发顺带解决了身份认证问题,为提高公钥分发的安全性又引入数字证书问题。
- CA的公钥如何安全的在网络上传输呢?给CA 也颁发证书,然后大家都无条件信任root CA,在操作系统、浏览器发布的时候便嵌入了root CA。
可以试想,若是加密算法私有,自然就没有密钥分发及之后的问题,代之就只加密算法本身的安全问题。
SSL/TLS 四次握手
加密
总结一下https设计到的一些加密知识
- 哈希,将任意长度的数据转化为固定长度的,验证数据是否被篡改
- 对称加密,加密和解密使用同一个密钥,对称加密的优点是速度快,缺点是密钥管理不方便,必须共享密钥
- 非对称加密,缺点是速度慢,优点是双方无需共享同一个密钥,密钥管理很方便
- 数字证书,提供可信的服务商公钥
安全的通信有以下要求
- 通信双方可信:是自己人;发了不能抵赖。
- 内容不被篡改
- 内容不可见
证书
逻辑链条:
先假设服务商是可信的
- 通信要加密,但对称加密密钥不易分发,也不能每次都一样
- 客户端持有服务端的公钥,可以每次非对称加密通信,但服务商的公钥谁都可以得到,服务商给我发的消息,别人虽然不能改,但也可以截获并解密。
- 先使用非对称加密 约定一个对称密钥,再用对称加密交流
如果服务商是不可信的,问题就变成了:如何拿到服务商的可信的公钥?/ 服务商如何证明自己是可信的? ==> 双方找一个都承认的第三方
- 客户端不能直接找服务商要,因为数据可能过黑客的手
- 本地存有ca的公钥(绝对可信,因为证书是事先浏览器、操作系统或手动添加的),服务商 拿出 ca 开的证明。这个ca的证明,就是为了提供可信的服务商公钥。
- 浏览器会尝试查CRL(证书吊销列表)和OCSP(在线证书检查),后者是前者的替代,即直接询问ca证书是否可信及在有效期内。但ca都在国外,因为证书不可篡改,所以谁给都一样(这一步待确认)
就好比谍报战里的接头戏码
- 两个彼此认识的特工接头会轻松一点,双方可能会经常变换下接头方式
- 第一次跟新来的特工接头,上级会告诉你xx点去xx等一个手里拿着xx的人,接头暗号是“hello/world”。此次,双方都认识的上级是CA,“hello/world” 便是对方的CA证书。
-
证书有什么,Chrome可以通过”settings ==> advanced setting ==> https/ssl ==> 管理证书” 查看证书内容。证书基本上是一个文本文件。
- 服务商的公钥
- 服务商的信息
- 对上述信息算一个签名,用ca自己的私钥加密一下
-
我如何验证证书?我拥有ca的公钥,对证书上的信息做一个签名, 解密证书上的签名,比对。
- 如果两个签名一样,签名一样,说明证书没被篡改
- 签名可以用ca公钥正确解密,说明是用ca私钥加密的,即证书是ca颁发的
结论,证书是可信的,那么证书上的内容,尤其是服务商的公钥是可信的。
私钥 | 公钥 | |
---|---|---|
ca | 一般浏览器安装时就有,存在ca根证书中 | |
服务商 | 浏览器验证服务商证书有效后,从服务商证书中拿到服务商公钥 |
证书的存储
浏览器保存了一个常用的 CA 证书列表,与此类似的,操作系统也一样保存有一份可信的证书列表。Java 在 JRE 的安装目录下也保存了一份默认可信的证书列表,可以使用 JRE 自带的 keytool 工具.
/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/security
--- cacerts
证书的格式
CA 在发布证书时,常常使用 PEM 格式,这种格式的好处是纯文本,内容是 BASE64 编码的,另外还有比较常用的二进制 DER 格式,在 Windows 平台上较常使用的 PKCS#12 格式等等。当然,不同格式的证书之间是可以相互转换的。
在 Java 平台下,证书常常被存储在 KeyStore 文件中,上面说的 cacerts 文件就是一个 KeyStore 文件(KeyStore 只是一种文件格式,java中使用keyStore文件存储加密相关的数据,证书是其中一种)。存储在 KeyStore 文件中的对象有三种类型:Certificate、PrivateKey 和 SecretKey 。Certificate 就是证书,PrivateKey 是非对称加密中的私钥,SecretKey 用于对称加密,是对称加密中的密钥。
KeyStore 文件根据用途,也有很多种不同的格式:JKS、JCEKS、PKCS12、DKS 等等。
java中的keyStore文件根据用途,分为两类:keyStore、TrustStore,对应两个类 KeyManager 和 TrustManager。前者负责管理自己的私钥等数据,后者负责存储一些可信任的证书。可以想见,如果我们改写 TrustManager 类,让其无论何时都返回true,即可绕过对证书的验证。
动态加载证书
大多数时候,本地只要有常用的ca根证书,即可验证大部分服务商。证书被验证可信后,浏览器或操作系统会将证书存储在本地(证书有效期内),当用户在浏览器中键入https地址时,直接开始同服务端商定对称算法和密钥,从而省去证书的获取和验证过程。
但是,当服务商证书不在Java 的 cacerts 文件中,或者无法通过ca证书链式推导,我们也可以手动添加。
- 12306之类的网站,证书基本可信,但不是向ca申请的
- 内部通信,证书自己生成,自己确认可信
添加方式
- 使用java keytool工具添加。有时候不具备权限,或要添加的机器过多
- 程序加载
这就是一些应用在使用时,要指定证书地址的缘故了。
- 应用作为服务端,client索要证书时,提供给client
- 应用作为客户端,直接加载服务端证书,以省去证书验证过程
制作证书
假设自己的nginx 对外提供https支持
- 自建ca 或第三方ca 机构
- 在nginx 机器上 创建一对儿rsa密钥(key文件);生成证书请求(csr文件)
- 将csr文件发送到ca服务器(第三方ca机构),得到nginx crt证书(crt或pem后缀)
- 访问nginx 的客户端持有ca 根crt证书,持有或获取 nginx 的crt 证书,即可与nginx 进行https通讯。
etcd 3.1 高可用集群搭建 具体描述了上述过程
- 创建ca-config.json,ca-csr.json,使用cfssl(CFSSL is CloudFlare’s PKI/TLS swiss army knife,tls/pki 工具集)
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
生成ca.csr,ca-key.pem,ca.pem
,ca.csr 一般用不上,ca-key.pem 表示ca的公钥信息(整个系统安全的关键,重点保护对象), ca.pem 表示根证书。 - 创建etcd-csr.json, 使用cfssl 根据根证书 创建etcd crt证书
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=frognew etcd-csr.json | cfssljson -bare etcd
,得到etcd.csr etcd-key.pem etcd.pem
-
etcdctl 访问 etcd时,需要
ETCDCTL_API=3 etcdctl --endpoints=https://192.168.56.101:2379 --cacert=/etc/etcd/ssl/ca.pem --cert=/etc/etcd/ssl/etcd.pem --key=/etc/etcd/ssl/etcd-key.pem member list
- etcd api 分为2和3,不同level的api 参数名不同
- etcdctl 请求时指定了
ca.pem、etcd.pem、etcd-key.pem
,目的就是根据根证书ca.pem 验证etcd 证书etcd.pem和etcd 公钥etcd-key.pem的合法性 - 以上条件具备后,
--endpoints=https://192.168.56.101:2379
表示etcdctl可以以https的方式进行通讯
ca和pki
所以呢,有一个PKI(Public Key Infrastructure)的概念,中文称作公钥基础设施。它提供公钥加密和数字签名服务的系统或平台,比如ca系统,浏览器和操作系统内置一些常用ca证书。通过协议和机制的约定,实现公钥的可信分发,进而建立起一个安全的网络环境。而数字证书最常见的格式是 X.509 ,所以这种公钥基础设施又称之为 PKIX 。
而在大公司内部,通常会建立私有的ca和pki体系。
安装过hadoop的同学都知道,有一个过程是,将所有slave节点的公钥交给master节点,这里slave节点类似于服务端,master节点类似于客户端。只是hadoop分发的是公钥,tls分发的是证书(分发证书也是为了分发公钥)。
小结
上文提到的都是单向非对称加密,对于安全性很高的场景(比如网银), 不仅客户端要验证服务端的合法性,服务端也要验证每个访问的客户端的合法性,对于这种场景,往往给每个用户发一个U盘,里面装的就是客户端的公钥和私钥对,用于双向非对称加密。