密钥
我们将未加密的内容称为明文,加密之后的内容称为密文。
简单来说,要加密一段明文,可以将这段内容输入到一个加密函数中,输出密文。但这种简单的加密方式存在被人盗取到加密函数从而破解明文的危险,且加密函数一般构成复杂,一旦被盗取更换成本较高。
于是人们想出了一个办法,在加密函数中再添加一个参数,这个参数只有通信双方知道,没有参数则无法正确解密出明文。这个参数被称为密钥。对于同一个加密函数而言,密钥值的不同则加密方式也不同,得出的密文也就不同。这样加密系统的安全性提高了,被盗取密钥之后更换密钥的成本也低了很多。常见的情景是加密函数都是使用公开的算法,加密方需要保存的仅仅是自己的密钥。
对称密钥加密
对称密钥加密就是加密与解密使用相同的是密钥值。
流行的对称密钥加密包括:
- DES
- TRiple-DES
- RC2
- RC4
对称密钥需要通信双方共享密钥。对互联网通信而言,不同的通信双方需要不同的对称密钥,如果有N个用户需要相互通信,总共需要密钥数N*(N-1)。
公开密钥加密
对称密钥加密存在需要密钥数太多以及传递密钥不方便的缺点,于是人们研究出非对称的密钥加密技术,即加密和解密的密钥不需要一样。常见的一种称为公开密钥加密。
公开密钥加密将通信一端的加密和解密密钥分成两个,其中加密密钥可以公开发布,也就是随便谁都可以使用该加密密钥为明文加密,但要解密这段密文只能靠该端私有的解密密钥。这解决了对称密钥加密中的缺点。其中公开的加密密钥称为公开密钥,私有的解密密钥称为私有密钥。
要保证公开密钥加密的可用性必须确保以下情况无法计算出私有密钥:
- 有公开密钥;
- 一段密文;
- 一段明文和使用公开密钥加密过的密文;
流行的公开密钥加密包括:
- RSA
- DH
- ECDHE
- ECDH
- DHE
公开密钥加密虽然更加简单安全但其加密算法运算比较慢,所以一般混合使用公开密钥加密和对称密钥加密的使用方式,即先通过公开密钥加密获取到对称密钥加密的密钥,再通过对称密钥加密传输数据。这种情况在后文说明。
数字签名
对称密钥加密和公开密钥加密都是将报文加密的技术。但加密能做的不止如此,还可以用加密算法来证明报文是谁编写的以及中途没有被篡改。数字签名就是这种技术。
数字签名是附加在报文上的特殊加密校验码。其使用了私有密钥加密生成校验码,除发送者外其他人都无法重新生成对应的校验码,这样就证明了报文的身份以及中途没有被人篡改过。
数字签名通常通过公开密钥技术产生,但使用方式相反。发送者首先为要签名内容生成报文摘要,使用签名函数并输入私有密钥作为参数,对报文摘要进行加密,生成签名并随报文一起发送出去。接收者通过附加了公开密钥参数的签名函数反函数将签名解密,并与生成的报文摘要进行对比,如果结果一致则代表报文无误。
常见的RSA加密系统可以同时用于公开密钥加密和数字签名。RSA加密系统将解码函数D作为签名函数使用,编码函数E作为解签名函数。
数字证书
单纯的公开密钥加密只适合对等的两端通信,对于常用的服务器-客户端通信模式仍存在一些问题。1是公开密钥加密只能证明报文确实是发送方发送的且没有篡改,但发送方本身是谁则无从得知,因为谁都可以生成公钥私钥对。如果把所有需要访问的网站的公钥都事先保存下来,数量巨大不说,如何发送这些公钥且如何证明保存的公钥确实是这个网站的公钥也是个问题。数字证书则可以解决这些问题。
数字证书是网络上的身份证明。一般包括如下内容:
- 证书格式版本号
- 证书序列号;
- 证书签名算法;
- 证书颁发者;
- 有效期;
- 对象名称;
- 对象公开密钥;
- 证书颁发者的数字签名;
其中颁发者的数字签名是通过数字证书的其余部分的报文摘要经证书签名算法及证书颁发者的私有密钥计算出的,用于验证数字证书的真实性。
任何人都能自行生成一个数字证书,但只有值得信任的组织(CA)生成的数字证书才会默认被浏览器信任。具体原因在下一节说明。
详解数字证书验证流程
关于浏览器验证网站数字证书的流程网上的资料一般讲的都不是很清楚。在查阅了不少资料后终于搞清楚这部分。
CA下发给网站的证书都是一个证书链,也就是一层一层的证书,从根证书开始,到下级CA,一层一层,最后一层就是网站证书。
浏览器收到服务器发送的证书后,需要验证其真实性。而证书的签名是通过签名算法和上级CA的私钥生成的。浏览器需要用上级CA的公钥才能解密签名,并与生成的指纹对比,那么问题来了,这个上级CA的公钥从哪来呢?
答案是此公钥来自于证书链该层的上级CA的证书明文内。单个X509v3证书由以下部分组成:
X.509v3证书由三部分组成:
- tbsCertificate (to be signed certificate),待签名证书。
- SignatureAlgorithm,签名算法。
- SignatureValue,签名值。
tbsCertificate又包含10项内容,在HTTPS握手过程中以明文方式传输:
- Version Number,版本号。
- Serial Number,序列号。
- Signature Algorithm ID,签名算法ID。
- Issuer Name,发行者。
- Validity period,有效时间。
- Subject name ,证书主体名称。
- Subject Public Key Info ,证书主体公钥信息,包含公钥算法和公钥值。
- Issuer Unique Identifier (optional),发行商唯一ID。
- Subject Unique Identifier (optional),主体唯一ID。
- Extensions (optional),扩展。
证书链由多个证书一层一层组成的,除了最底层的网站证书的公钥是给用户加密报文外,其他层证书中的公钥均用于解密底层的证书指纹签名。最高层的根证书是自签名的,也就是自己颁发给自己,所以它的公钥不仅用来解密下层的签名,也用来给自己的签名解密。
验证证书是否真实的任务完成了,那么证书是否可靠如何验证呢?一句话,只要根证书可靠,整个证书链就可靠,而根证书是否可靠要看这个根证书是否在操作系统或浏览器内置的可信根证书内,在的话就可信。
HTTPS
HTTPS是在HTTP报文发送给TCP之前对报文进行加密的安全协议。使用443端口进行通信。
普通的HTTP有如下四层:
- 应用层HTTP
- 传输层TCP
- 网络层IP
- 数据链路层
HTTPS多了一个安全层:
- 应用层HTTP
- 安全层SSL/TLS
- 传输层TCP
- 网络层IP
- 数据链路层
证书密钥验证都是在安全层验证。常用的SSL/TLS编程实现库是OPENSSL。
HTTPS实际验证过程
此部分内容主要参考《SSL/TLS协议运行机制的概述》http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html
实际的HTTPS验证过程如下:
ClientHello阶段
- 支持的协议版本,比如TLS 1.0版;
- 一个客户端生成的随机数,稍后用于生成”对话密钥”;
- 支持的加密方法,比如RSA公钥加密;
- 支持的压缩方法;
ServerHello阶段
- 确认使用的加密通信协议版本;
- 一个服务器生成的随机数,稍后用于生成”对话密钥”;
- 确认使用的加密方法,比如RSA公钥加密;
- 服务器证书;
对于需要验证用户证书的还会包含请求要求用户提供证书。
客户端回应
客户端收到回应后首先验证服务器证书:
- 是否由可信CA颁布;
- 证书中域名是否与实际域名一致;
- 是否在有效期内;
证书没问题的话客户端会回应以下内容:
- 一个随机数(pre-master key)。该随机数用服务器公钥加密,防止被窃听;
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送;
- 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验;
此时通信双方都有了这三个随机数。通过商定的加密方法根据三个随机数生成一个相同的会话密钥SessionSecret,用于之后的对称加密。
服务器回应
服务器收到回应后计算出SessionSecret,并发送以下内容给客户端:
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送;
- 服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供客户端校验
这样HTTPS握手过程就结束了,之后就是通过HTTP发送经过对称加密的报文。
参考资料: