前言:
HTTP 如何保证安全性呢?基本上所有的人都会脱口而出:使用 HTTPS 协议。99.9% 的人都知道 HTTPS 会将传输的内容进行加密,但是接着问具体加密的过程和步骤,很多人就哑口无言了。
简介
HTTPS
HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。 它是一个URI scheme(抽象标识符体系),句法类同http:体系。用于安全的HTTP数据传输。https:URL表明它使用了HTTPS,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。这个系统的最初研发由网景公司进行,提供了身份验证与加密通讯方法,现在它被广泛用于万维网上安全敏感的通讯,例如交易支付方面
SSL,(Secure Socket Layer 安全套接字层),为Netscape(网景公司)所研发,用以保障在Internet上数据传输之安全。SSL目前有三个版本,SSL1.0、SSL2.0、SSL3.0。它已被广泛地用于Web浏览器与服务器之间的身份认证和加密数据传输。
SSL利用数据加密、身份验证和消息完整性验证机制,为网络上数据的传输提供安全性保证。SSL支持各种应用层协议。由于SSL位于应用层和传输层之间,所以可以为任何基于TCP等可靠连接的应用层协议提供安全性保证。
SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。
TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。
TLS 1.0是IETF(Internet Engineering Task Force,Internet工程任务组)制定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本,可以理解为SSL 3.1,它是写入了 RFC的。该协议由两层组成: TLS 记录协议(TLS Record)和 TLS 握手协议(TLS Handshake)。较低的层为 TLS 记录协议,位于某个可靠的传输协议(例如 TCP)上面。
SSL/TLS协议提供的服务主要有:
1、认证用户和服务器,确保数据发送到正确的客户机和服务器;
2、加密数据以防止数据中途被窃取;
3、维护数据的完整性,确保数据在传输过程中不被改变。
SSL安全机制
1、身份验证机制
基于证书利用数字签名方法对服务器和客户端进行身份验证,其中客户端的身份验证是可选的。
2、数据传输的机密性
利用对称密钥算法对传输的数据进行加密。
3、消息完整性验证
消息传输过程中使用MAC算法来检验消息的完整性。
1.2 TLS与SSL的差异
1、版本号:TLS记录格式与SSL记录格式相同,但版本号的值不同,TLS的版本1.0使用的版本号为SSLv3.1。
2、报文鉴别码:SSLv3.0和TLS的MAC算法及MAC计算的范围不同。TLS使用了RFC-2104定义的HMAC算法。SSLv3.0使用了相似的算法,两者差别在于SSLv3.0中,填充字节与密钥之间采用的是连接运算,而HMAC算法采用的是异或运算。但是两者的安全程度是相同的。
3、伪随机函数:TLS使用了称为PRF的伪随机函数来将密钥扩展成数据块,是更安全的方式。
4、报警代码:TLS支持几乎所有的SSLv3.0报警代码,而且TLS还补充定义了很多报警代码,如解密失败(decryption_failed)、记录溢出(record_overflow)、未知CA(unknown_ca)、拒绝访问(access_denied)等。
5、密文族和客户证书:SSLv3.0和TLS存在少量差别,即TLS不支持Fortezza密钥交换、加密算法和客户证书。
6、certificate_verify和finished消息:SSLv3.0和TLS在用certificate_verify和finished消息计算MD5和SHA-1散列码时,计算的输入有少许差别,但安全性相当。
7、加密计算:TLS与SSLv3.0在计算主密值(master secret)时采用的方式不同。
8、填充:用户数据加密之前需要增加的填充字节。在SSL中,填充后的数据长度要达到密文块长度的最小整数倍。而在TLS中,填充后的数据长度可以是密文块长度的任意整数倍(但填充的最大长度为255字节),这种方式可以防止基于对报文长度进行分析的攻击。
HMAC
HMAC(Keyed-hash message authentication code),即密钥散列消息认证码,又称散列消息认证码,是一种通过特别计算方式之后产生的消息认证码(MAC),使用密码散列函数,同时结合一个加密密钥,它可以用来保证数据的完整性,同时可以用来做某个消息的身份验证,由RFC2104定义,数学公式为:
其中:
H为密码散列函数(如MD5或SHA-1)
K为密钥(secret key)
m是要认证的消息
K’是从原始密钥K导出的另一个秘密密钥(如果K短于散列函数的输入块大小,则向右填充(Padding)零;如果比该块大小更长,则对K进行散列)
||代表串接
⊕代表异或(XOR)
opad是外部填充(0x5c5c5c…5c5c,一段十六进制常量)
ipad是内部填充(0x363636…3636,一段十六进制常量)
TLS的主要增强内容
TLS的主要目标是使SSL更安全,并使协议的规范更精确和完善。TLS 在SSL v3.0 的基础上,提供了以下增强内容:
1、更安全的MAC算法
2、更严密的警报
3、“灰色区域”规范的更明确的定义
TLS对于安全性的改进
1、对于消息认证使用密钥散列法:TLS 使用“消息认证代码的密钥散列法”(HMAC),当记录在开放的网络(如因特网)上传送时,该代码确保记录不会被变更。SSLv3.0还提供键控消息认证,但HMAC比SSLv3.0使用的(消息认证代码)MAC 功能更安全。
2、增强的伪随机功能(PRF):PRF生成密钥数据。在TLS中,HMAC定义PRF。PRF使用两种散列算法保证其安全性。如果任一算法暴露了,只要第二种算法未暴露,则数据仍然是安全的。
3、改进的已完成消息验证:TLS和SSLv3.0都对两个端点提供已完成的消息,该消息认证交换的消息没有被变更。然而,TLS将此已完成消息基于PRF和HMAC值之上,这也比SSLv3.0更安全。
4、一致证书处理:与SSLv3.0不同,TLS试图指定必须在TLS之间实现交换的证书类型。
5、特定警报消息:TLS提供更多的特定和附加警报,以指示任一会话端点检测到的问题。TLS还对何时应该发送某些警报进行记录。
SSL协议基本运行过程
SSL位于应用层和传输层之间,它可以为任何基于TCP等可靠连接的应用层协议提供安全性保证。SSL协议本身分为两层:
上层为SSL握手协议(SSL handshake protocol)、SSL密码变化协议(SSL change cipher spec protocol)和SSL警告协议(SSL alert protocol);
底层为SSL记录协议(SSL record protocol)。
解析:
SSL握手协议:是SSL协议非常重要的组成部分,用来协商通信过程中使用的加密套件(加密算法、密钥交换算法和MAC算法等)、在服务器和客户端之间安全地交换密钥、实现服务器和客户端的身份验证。
SSL密码变化协议:客户端和服务器端通过密码变化协议通知对端,随后的报文都将使用新协商的加密套件和密钥进行保护和传输。
SSL警告协议:用来向通信对端报告告警信息,消息中包含告警的严重级别和描述。
SSL记录协议:主要负责对上层的数据(SSL握手协议、SSL密码变化协议、SSL警告协议和应用层协议报文)进行分块、计算并添加MAC值、加密,并把处理后的记录块传输给对端。
基本运行过程
1、客户端向服务器端索要并验证公钥。
2、双方协商生成"对话密钥"。
3、双方采用"对话密钥"进行加密通信。
其中,前两个阶段,被称为“握手阶段”。
握手阶段详细过程
"握手阶段"涉及四次通信,该阶段的所有通信都是明文的。
由于非对称加密的速度比较慢,所以它一般用于密钥交换,双方通过公钥算法协商出一份密钥,然后通过对称加密来通信,当然,为了保证数据的完整性,在加密前要先经过HMAC的处理。
TLS握手阶段是发生在TCP建连之后开始进行的,握手其实就是在协商,协商加解密协议所需要的一些参数信息等内容。
TLS握手过程有单向验证和双向验证之分,简单解释一下,单向验证就是server端将证书发送给客户端,客户端验证server端证书的合法性等,例如百度、新浪、google等普通的https网站,双向验证则是不仅客户端会验证server端的合法性,同时server端也会验证客户端的合法性,例如银行网银登陆,支付宝登陆交易等。
SSL缺省只进行server端的认证,客户端的认证是可选的。以下是其流程图:
1、客户端发出请求(ClientHello)
由于客户端(如浏览器)对一些加解密算法的支持程度不一样,但是在TLS协议传输过程中必须使用同一套加解密算法才能保证数据能够正常的加解密。在TLS握手阶段,客户端首先要告知服务端,自己支持哪些加密算法,所以客户端需要将本地支持的加密套件(Cipher Suite)的列表传送给服务端。除此之外,客户端还要产生一个随机数,这个随机数一方面需要在客户端保存,另一方面需要传送给服务端,客户端的随机数需要跟服务端产生的随机数结合起来产生后面要讲到的 Master Secret 。
综上,在这一步,客户端主要向服务器提供以下信息:
解析:
Record Layer:记录层,记录了该内容的类型为Handshake(22),22则对应下方十六进制的16;
SSL Version,用于服务端验证支持的协议版本号。
Version:TLS1.0(0x0301),该标识记录了TLS1.0实际上是基于ssl3.1而来的,对应下方十六进制为0301;
Handshake Type:Client Hello(1),标识了这个握手类型是Client Hello阶段,对应下方十六进制为01;
Client Random1,随机数用于后面对话密钥的生成。
GMT Unix Time时间则为从1970年1月1日至今所经历的秒数,Random
Bytes则为32个字节的随机数,严格点来说就是伪随机数,因为真正的随机数是不存在的;
RFC5246定义如下:
Session ID Length:顾名思义就是客户端想要用于该连接的Session id,初始值为空,也就是看到的0,因为是第一次访问没有该值;
Support Ciphers,用于服务端选择支持的加密算法。
Cipher Suites(15 suites):该字段则为客户端所支持的加密套件,共15套;
压缩算法,用于压缩的算法。
Extension:该字段就是下文中提到过的SNI相关字段,扩展字段,其中就标识了server name即主机名是什么及字段长度,这样就能在握手时获取主机名并匹配到相对应的证书了;
客户端请求中原本是不包括服务器域名的,也就是说,理论上只能包含一个服务器,对于支持多个虚拟机的服务器来说,这并不方便,不能知道向哪个服务器请求证书。为了解决这个问题,在Client Hello报文中了,扩展信息中,增加了sever_name这个扩展信息,通过域名进行区分。
SNI(Server Name Indication),
SNI(Server Name Indication),即服务器名称指示,是一个扩展的TLS协议,在该协议下,在握手过程开始时就可以通过客户端告诉它正在连接的服务器的主机名称,这就允许了服务器在相同的IP地址和TCP端口号上绑定多个证书了,并且因此允许在相同的IP地址上提供多个安全的https网站,它与虚拟主机概念相同。
SNI通过让客户端发送主机名作为TLS协商的一部分来解决此问题,这就使得服务器能够提前选择正确的主机名,并向浏览器提供包含正确名称的证书。SNI需要客户端浏览器和server端程序同时支持,目前主流的浏览器和server端程序均已支持了该特性,近年来IE6的市场份额应该可以小到忽略不计了。
以百度为例,SNI请求的字段数据包如下例子:
非对称加密算法:
RSA:RSA是1977年由罗纳德·李维斯特(Ron Riverst)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的,当时三人都在麻省理工学院工作,RSA就是他们三人姓氏开头字母的缩写拼在一起组成的。
RSA算法的安全性基于大数分解质因子的困难性,由于人们一直未找到对大数进行因子分解的有效方法,所以RSA在目前看来依然是安全的,RSA算法既可用于加密,也可用于签名,是目前应用最广的公钥算法。
DH(Diffie-Hellman):是一种安全的密钥交换协议,它可以让双方在完全没有对方任何预先信息的条件下通过不安全通道创建一个密钥,这个密钥可以在后续的通信中做为对称密钥来加密通讯内容。
2、服务器回应(Sever Hello、Certificate、Server Key Exchange、Server Hello Done)
上图中,从Server Hello到Server Done,有些服务端的实现是每条单独发送,有服务端实现是合并到一起发送。Sever Hello和Server Done都是只有头没有内容的数据。
服务端在接收到客户端的Client Hello之后,服务端需要将自己的证书发送给客户端。这个证书是对于服务端的一种认证。例如,客户端收到了一个来自于称自己是www.alipay.com的数据,但是如何证明对方是合法的alipay支付宝呢?这就是证书的作用,支付宝的证书可以证明它是alipay,而不是财付通。证书是需要申请,并由专门的数字证书认证机构(CA)通过非常严格的审核之后颁发的电子证书。颁发证书的同时会产生一个私钥和公钥。私钥由服务端自己保存,不可泄漏。公钥则是附带在证书的信息中,可以公开的。证书本身也附带一个证书电子签名,这个签名用来验证证书的完整性和真实性,可以防止证书被串改。另外,证书还有个有效期。
在服务端向客户端发送的证书中没有提供足够的信息(证书公钥)的时候,还可以向客户端发送一个 Server Key Exchange,
此外,对于非常重要的保密数据,服务端还需要对客户端进行验证,以保证数据传送给了安全的合法的客户端。服务端可以向客户端发出 Cerficate Request 消息,要求客户端发送证书对客户端的合法性进行验证。比如,金融机构往往只允许认证客户连入自己的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。
跟客户端一样,服务端也需要产生一个随机数发送给客户端。客户端和服务端都需要使用这两个随机数来产生Master Secret。
最后服务端会发送一个Server Hello Done消息给客户端,表示Server Hello消息结束了。
综上,在这一步,服务器的回应包含以下内容:
1、确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。
2、一个服务器生成的随机数(Sever Random),稍后用于生成"对话密钥"。
3、确认使用的加密方法,比如RSA公钥加密。
4、服务器证书(Certificate)。
5、支持的一些SSL/TLS扩展。
服务器发送Sever Hello后,向客户端发送证书信息(Certificate)
服务器发送Certificate后,开始发送sever key exchange,向客户端发送生成密钥的信息。这个发送只限于使用DH算法(DH算法生成的密钥是由客户端参数和服务端参数根据规则计算得出),如果是RSA算法不需要发送此请求。
服务器DH参数(Sever Key Exchange)
当服务器发送Sever Hello Done,表明所有的参数发送完成。
PS:此为单向验证,若是双向验证,需要在Sever Hello Done之前发送Certificate Request,表示需要客户端提供证书,内容为:
1、客户端应当提供的证书类型
2、服务端可以接受的证书列表
3、客户端回应 (Client Key Exchange、 Change Chiper Spec、Encrypted Handshake Message)
Client Key Exchange
生成一个随机数,如果采用的是RSA加密方式则取出证书中的公钥,生成随机数。如果采用的是DH算法则使用双发的DH加密参数和规则生成随机数。
客户端key交换,并且客户端使用change cipher spec通知server端开始使用加密报文传输数据,在此之前的信息都是明文的,因此我可以通过wireshark看到。
在此阶段,客户端将通过RSA算法生成一个48字节的premaster secret,即预主密钥,这个密钥中包含了客户端tls的版本号信息,如果有中间人共计,有意降低tls版本的话,则会马上终止发送数据。
这个premaster secret是一个保密的key,只要被截获就可以结合之前明文传输的伪随机数计算出最终的master secret即主密钥。因此该密钥会通过公钥证书加密传送至server端,server端通过私钥进行解密获取预主密钥,此时客户端和server端都有了相同的伪随机数及预主密钥。
Certificate Verify
如果服务端需要对客户端进行验证,在客户端收到服务端的 Server Hello 消息之后,首先需要向服务端发送客户端的证书,让服务端来验证客户端的合法性。
接着,客户端需要对服务端的证书进行检查,如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。如果证书没有问题,客户端就会从服务器证书中取出服务器的公钥。然后,向服务器发送下面三项信息:
1、一个随机数(Pre Master Secret)。该随机数用服务器公钥加密,防止被窃听。
2、编码改变通知(Change Chiper Spec),表示随后的信息都将用双方商定的加密方法和密钥发送。
3、客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。
上面第一项的随机数,是整个握手阶段出现的第三个随机数,它是客户端使用一些加密算法(例如:RSA, Diffie-Hellman)产生一个48个字节的Key,这个Key叫 PreMaster Secret,很多材料上也被称作 PreMaster Key。
至于为什么一定要用三个随机数,来生成"会话密钥",dog250解释得很好:
"不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。
对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,再加上hello消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。
pre master的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,随机性增加的可不是一。"
Change Cipher Spec
Change Cipher Spec是一个独立的协议,体现在数据包中就是一个字节的数据,用于告知服务端,客户端已经切换到之前协商好的加密套件(Cipher Suite)的状态,准备使用之前协商好的加密套件加密数据并传输了。
在Change Chiper Spec传输完毕之后,客户端会使用之前协商好的加密套件和Session Secret加密一段 Finish 的数据传送给服务端,此数据是为了在正式传输应用数据之前对刚刚握手建立起来的加解密通道进行验证。
** Encrypted Handshake Message **
Encrypted Handshake Message,通过前两次的随机数以及最后一次的随机数(Pre Master Secret)使用确定的加密算法生成对话密钥 (Session Secret),使用对话密钥加密报文。
PS:如果是双向认证,客户端还会Certificate和Certificate Verify报文。Certificate是客户端的证书,Certificate Verify是客户端拥有的所有握手过程中的签名信息。服务端对证书以及信息进行确认,如果发现证书和信息有误则终止SSL/TLS连接。
4、服务器的最后回应(New Session Ticket, Change Chiper Spec, Encrypted Handshake Message)
New Session Ticket
该数据包主要是server端向客户端发送新的session ticket,因为最开始并没有这个信息,并通知客户端开始使用加密方式传输数据。
该session ticket就相当于普通网站中的session,当浏览器在次发送请求或者中间网络原因连接被断开之后,client hello阶段携带该session id,则认为是同一个人访问,不在进行证书交互阶段,该session id的复用也是优化的一点,最后会提到。同样的这个数据也是被加密的,server端得到后进行解密即可快速完成握手。其中该字段不仅包含session ticket,还包含ticket的寿命,即过期时间,长度等。
服务端在接收到客户端传过来的 PreMaster 加密数据之后,使用私钥对这段加密数据进行解密,并对数据进行验证,也会使用跟客户端同样的方式生成 Session Secret,一切准备好之后,会给客户端发送一个 ChangeCipherSpec,告知客户端已经切换到协商过的加密套件状态,准备使用加密套件和 Session Secret加密数据了。之后,服务端也会使用 Session Secret 加密一段 Finish 消息发送给客户端,以验证之前通过握手建立起来的加解密通道是否成功。
根据之前的握手信息,如果客户端和服务端都能对Finish信息进行正常加解密且消息正确的被验证,则说明握手通道已经建立成功,接下来,双方可以使用上面产生的Session Secret对数据进行加密传输了。
服务端收到客户端的加密报文之后进行解密和校验,若成功生成一个session ticket(解释见下文)。然后作出回应:
1、服务端传输改变通知(Change Chiper Spec)
2、服务端第一个加密报文(Encrypted Handshake Message)
Change Chiper Spec与客户端发送的含义一致,通知客户端。
** Encrypted Handshake Message**与客户端发送的第一报文含义一致,用于客户端进行报文验证。
客户端确定密钥以及验证成功之后,整个握手过程就基本完成,以后的报文都是通过协商好的密钥进行加密。
会话恢复(session ID 和 session ticket)
这里不得不提详细提一下session ticket和session id这两个角色,简单的理解就是session id就是一个session会话标识,当下次访问时携带该标识则认为是同一个人访问,但是假如轮询到集群中其它服务器,则可能无法识别该session id,因为是初次建连服务器给的,而session id是由服务器存储的主要信息,是需要占用服务器内存资源的,且不易扩展。Session id的存储及复用共享需要使用redis或memcache来实现。
也因此session ticket应运而生了,该字串中包含了当时会话所使用的一些信息,解密出来即可快速重用(RFC5077对此有详细释义),session ticket存储在客户端,新会话后,服务器通过一个自己知道的密钥ticket key将本次会话状态加密,发送给客户端,客户端保存该ticket,下次建连时候发送给server端,该方式的问题是集群中所有server设备使用相同的ticket key,因此也需要考虑该key的轮转及轮转时新旧key兼容的问题。
nginx会话缓存配置:ssl_session_cachessl_session_ticket_key
**session ID **
Session Identifier(会话标识符),是 TLS 握手中生成的 Session ID。服务端可以将 Session ID 协商后的信息存起来,浏览器也可以保存 Session ID,并在后续的 ClientHello 握手中带上它,如果服务端能找到与之匹配的信息,就可以完成一次快速握手。
**session ticket **
Session Identifier 机制有一些弊端,
例如:
1)负载均衡中,多机之间往往没有同步 Session 信息,如果客户端两次请求没有落在同一台机器上就无法找到匹配的信息;
2)服务端存储 Session ID 对应的信息不好控制失效时间,太短起不到作用,太长又占用服务端大量资源。
而 Session Ticket(会话记录单)可以解决这些问题,Session Ticket 是用只有服务端知道的安全密钥加密过的会话信息,最终保存在浏览器端。浏览器如果在 ClientHello 时带上了 Session Ticket,只要服务器能成功解密就可以完成快速握手。
master secret
主密钥,用来对称加密传输数据,主密钥通过客户端random、server端random及premaster secret得到,算法如下:
master_secret= PRF(pre_master_secret, “master secret”, ClientHello.random +ServerHello.random)
其实我这里并没有理解master secret还没有呢,为啥也参与运算了。
这里还有一个key block的概念,我因为理解的不太透彻,只能浅显的描述以下了,想仔细的研究还得去看RFC文档。
master secret是有一系列的hash值组成的,它将作为数据加解密相关的secret的key material。
Sessionsecret是从key material中获取,key material经过12次迭代计算,产生12个hash值,分成了6个元素,分别是:
ClientMac(Message Authentication Code)key、server Mackey、client encryption key、server encryption key、clientIV(Initialization Vector)、serverIV
我理解最终的对称加密就是使用这几个hash值进行加密解密以及数据完整性的校验,因为客户端和server端两头都有了这几个数据。
因为对其理解的不太透彻,故此贴出部分RFC释义
总结
SSL客户端(也是TCP的客户端)在TCP链接建立之后,发出一个ClientHello来发起握手,这个消息里面包含了自己可实现的算法列表和其它一些需要的消息,SSL的服务器端会回应一个ServerHello,这里面确定了这次通信所需要的算法,然后发过去自己的证书(里面包含了身份和自己的公钥)。Client在收到这个消息后会生成一个秘密消息,用SSL服务器的公钥加密后传过去,SSL服务器端用自己的私钥解密后,会话密钥协商成功,双方可以用同一份会话密钥来通信了。
HTTPS通信的步骤
①客户端发送报文进行SSL通信。报文中包含客户端支持的SSL的指定版本、加密组件列表(加密算法及密钥长度等)。
②服务器应答,并在应答报文中包含SSL版本以及加密组件。服务器的加密组件内容是从接受到的客户端加密组件内筛选出来的。
③服务器发送报文,报文中包含公开密钥证书。
④服务器发送报文通知客户端,最初阶段SSL握手协商部分结束。
⑤SSL第一次握手结束之后,客户端发送一个报文作为回应。报文中包含通信加密中使用的一种被称Pre-master secret的随机密码串。该密码串已经使用服务器的公钥加密。
⑥客户端发送报文,并提示服务器,此后的报文通信会采用Pre-master secret密钥加密。
⑦客户端发送Finished报文。该报文包含连接至今全部报文的整体校验值。这次握手协商是否能够完成成功,要以服务器是否能够正确解密该报文作为判定标准。
⑧服务器同样发送Change Cipher Spec报文。
⑨服务器同样发送Finished报文。
⑩服务器和客户端的Finished报文交换完毕之后,SSL连接就算建立完成。
⑪应用层协议通信,即发送HTTP响应。
⑫最后由客户端断开链接。断开链接时,发送close_nofify报文
HTTPS 中的 SSL 握手建立过程
1、首先,客户端 A 访问服务器 B ,比如我们用浏览器打开一个网页 https://www.baidu.com ,这时,浏览器就是客户端 A ,百度的服务器就是服务器 B 了。这时候客户端 A 会生成一个随机数1,把随机数1 、自己支持的 SSL 版本号以及加密算法等这些信息告诉服务器 B 。
2、服务器 B 知道这些信息后,确认一下双方的加密算法,然后服务端也生成一个随机数 B ,并将随机数 B 和 CA 颁发给自己的证书一同返回给客户端 A 。
3、 客户端 A 得到 CA 证书后,会去校验该 CA 证书的有效性,校验方法在上面已经说过了。校验通过后,客户端生成一个随机数3 ,然后用证书中的公钥加密随机数3 并传输给服务端 B 。服务端 B 得到加密后的随机数3,然后利用私钥进行解密,得到真正的随机数3。
4、最后,客户端 A 和服务端 B 都有随机数1、随机数2、随机数3,然后双方利用这三个随机数生成一个对话密钥。之后传输内容就是利用对话密钥来进行加解密了。这时就是利用了对称加密,一般用的都是 AES 算法。
5、 客户端 A 通知服务端 B ,指明后面的通讯用对话密钥来完成,同时通知服务器 B 客户端 A 的握手过程结束。
6、服务端 B 通知客户端 A,指明后面的通讯用对话密钥来完成,同时通知客户端 A 服务器 B 的握手过程结束。SSL 的握手部分结束,SSL 安全通道的数据通讯开始,客户端 A 和服务器 B 开始使用相同的对话密钥进行数据通讯。
到此,SSL 握手过程就讲完了。可能上面的流程太过于复杂,我们简单地来讲:
客户端和服务端建立 SSL 握手:客户端通过 CA 证书来确认服务端的身份;互相传递三个随机数,之后通过这随机数来生成一个密钥;互相确认密钥,然后握手结束;数据通讯开始,都使用同一个对话密钥来加解密;
我们可以发现,在 HTTPS 加密原理的过程中把对称加密和非对称加密都利用了起来。即利用了非对称加密安全性高的特点,又利用了对称加密速度快,效率高的好处。
中间人攻击
中间人攻击(英语:Man-in-the-middle attack,缩写:MITM),指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。
** 中间人攻击路程:**
流程如下:
1、截获客户端与服务器通信的通道
2、然后在 SSL 建立连接的时候,进行中间人攻击
3、将自己伪装成客户端,获取到服务器真实有效的 CA 证书(非对称加密的公钥)
4、将自己伪装成服务器,获取到客服端的之后通信的密钥(对称加密的密钥)
5、有了证书和密钥就可以监听之后通信的内容了
charles抓包原理
抓取https包的时候,青花瓷会要求使用者 对抓包的设备(手机或其他设备)
,安装一个证书,安装这个证书的时候,其实是安装了一个根证书(允许颁发CA的一个证书机构的根证书),当你安装了该根证书之后,该证书机构颁发的其他证书,默认都会被你的系统所信任,这个就是青花瓷完成https抓包的一个重要前提!!
1、当客户端Client对服务器Server发送请求(带着随机数和加密算法),由于青花瓷做了代理,请求被青花瓷拦截,处理(青花瓷的角色现在对于Client来说是服务器),青花瓷将客户端带的随机数和加密算法处理,然后返回自己的证书通过客户端校验,获取到客户端提交的请求参数等数据,
2、青花瓷作为客户端(自己去产生随机数和携带支持的加密算法)去请求刚刚Client想要请求的Server,然后,Server会和青花瓷完成上面讲的那个完整的校验,并且读取青花瓷带错来的具体请求,返回正常的数据结果.
3、青花瓷得到服务器数据的返回结果之后,开始继续和过程1中的Client以服务器的身份,去做处理,首先收到客户端的随机数和加密算法,自己生成一个随机数和选择一个客户端的加密算法,然后重要* 青花瓷会返回一个伪造的CA证书(公钥和真实的server不一样,但是域名是一样的,或者说,除了域名是一致的,其他的都不是一致的,而且这个签发机构是青花瓷之前让你安装的根证书 签发的,所以,当返回这个证书的时候,你的客户端的信任链是可以完成的,会被系统信任),然后Client在这个伪造的证书(对于青花瓷和Client是真实证书(验证信任链和证书信息都通过了),但是和真实的域名对应的证书来看,是伪造证书)的基础上,和青花瓷通信,然后青花瓷再和Server通信,成了一个中间人的角色,这样,整个过程的数据传输,都被青花瓷给监听到了
在此,中间人攻击的过程 就完成了
** 防止抓包 **
客户端本地做证书校验,并且设置不仅仅校验公钥,设置完整的正式校验模式。
+(AFSecurityPolicy*)customSecurityPolicy
{
// /先导入证书
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@“test” ofType:@“cer”];//证书的路径
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
// AFSSLPinningModeCertificate 使用证书验证模式 (AFSSLPinningModeCertificate是证书所有字段都一样才通过认证,AFSSLPinningModePublicKey只认证公钥那一段,AFSSLPinningModeCertificate更安全。但是单向认证不能防止“中间人攻击”)
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
// allowInvalidCertificates 是否允许无效证书(也就是自建的证书),默认为NO
// 如果是需要验证自建证书,需要设置为YES
securityPolicy.allowInvalidCertificates = YES;
//validatesDomainName 是否需要验证域名,默认为YES;
//假如证书的域名与你请求的域名不一致,需把该项设置为NO;如设成NO的话,即服务器使用其他可信任机构颁发的证书,也可以建立连接,这个非常危险,建议打开。
//置为NO,主要用于这种情况:客户端请求的是子域名,而证书上的是另外一个域名。因为SSL证书上的域名是独立的,假如证书上注册的域名是www.google.com,那么mail.google.com是无法验证通过的;当然,有钱可以注册通配符的域名*.google.com,但这个还是比较贵的。
//如置为NO,建议自己添加对应域名的校验逻辑。
securityPolicy.validatesDomainName = YES;
NSSet<NSData*> * set = [[NSSet alloc]initWithObjects:certData , nil];
securityPolicy.pinnedCertificates = set;
return securityPolicy;
}
** SSL Pinning技术**
客户端和服务端需要在本地约定好一个本地证书,获取到数据之后在基于上面的验证基础上再验证本地证书是否相同,这样就有效的避免了中间人攻击,而这种安全技术就是SSL Pinning技术。
CA中心
认证机构CA(Certificate Authority)在https中是一个很重要的角色,CA是PKI的核心执行机构,是PKI(Public key Infrastructure 公钥基础设施)的主要组成部分,通常称之为认证中心,从广义上讲,认证中心还应该包括证书申请注册机构RA(Registration Authority),它是数字证书的申请注册、证书签发的管理机构。客户端是怎么验证该证书的颁发机构即CA中心是合法有效的呢,其实在系统浏览器中有预埋CA中心的根证书,在其中的根证书为可信任机构,如图:
CA的主要职责
a、笼统的说CA中心负责证书的签发和管理等;
b、验证并标识证书申请者的身份,对证书申请者的信用度、申请证书的目的、身份的真实可靠性等问题进行审查,确保证书与身份绑定的准确性;
c、确保CA用于签名证书的非对称密钥的质量和安全性;
d、管理证书信息资料,管理证书序号和CA标识,确保证书主体标识的唯一性,防止证书主 体名字的重复。在证书使用中确定并检查证书的有效期,保证不使用过期或已作废的证书, 确保网上交易安全,发布和维护作废证书列表(CRL)。
由此可见,CA是保证电子商务、网上银行、互联网环境健康等的权威性、可信任和公正的第三方机构。
认证机构的工作
认证机构会生成一对秘钥, 公钥和私钥
公钥证书的生成包括了两部分内容
1、数字签名
2、服务器公钥
其中数字签名的生成过程是:
1、服务器公钥 经过数字摘要算法 生成数字指纹
2、把生成的数字指纹 在用认证机构的私钥加密 生成数字签名
客户端如何校验 CA 证书的步骤
服务器将公钥证书发送给客户端, 客户端验证公钥证书从而确保公钥的合法性。
1、客户端取出提前内置在手机内部的认证机构的公钥
2、用认证机构的公钥去解密公钥证书里的数字签名 从而得到数字指纹
3、客户端对公钥证书的服务器公钥进行数字摘要算法 从而生成数字指纹
4、对比客户端自己生成的数字指纹(第3步)和解密得到的数字指纹(第2步)是否一致 如果一致则公钥证书验证通过,服务端是可以被信任的;如果不相等,那么就说明该证书是错误的,可能被篡改了,浏览器会给出相关提示,无法建立起 HTTPS 连接。除此之外,还会校验 CA 证书的有效时间和域名匹配等。
公钥
公钥(Public-key),即所谓的公共证书,由CA中心颁发的合法文件,可以在互联网传播,谁都可以轻易获取到。公钥证书文件的扩展名实际上只是一种使用习惯上的区别,后缀包括但不仅限于crt、cer、key、der、pem,pem可能包含了公钥和私钥文件,通常可以从pem文件中导出公钥和私钥。公钥中包含颁发给哪个域名,公司名,加密算法,组织机构,有效期等等信息,示例如图:
当然如果说一个证书只能绑定一个域名的话,100个域名就要100个证书了,这样管理和费用成本都会显著增加,根据不同用户的不同需求,同时CA中心也会根据不同国家国情推出不同的产品,例如一个证书绑定多个单域名或泛域名,这些我们都是可以通过公钥查看出来的,示例如图:
私钥
私钥(private-key),即通常就叫所谓的私钥,私钥在生成CSR文件的时候同时生产,后缀通常为.key,由使用者自己保管,不可在互联网传播,极其重要。
CSR文件
CSR(Cerificate Signing Request)文件,即证书请求文件,用于发送给CA中心用来生产公钥,该文件在生成的时候会填写一些基本信息,诸如国家代码、公司名、省份城市、管理员邮箱等等信息,可以在线生成也可以通过openssl生成,例:
openssl req -new -nodes -newkey rsa:2048 -keyout xxx.key-out xxx.csr