Https:从tcp建立连接到https接收到第一个数据包,到底发生了什么?

转自:

http://blog.csdn.net/arthur_killer/article/details/71405249

https 建立连接过程

Abstract

https 是基于http 和 ssl(安全套接字层) 的安全传输协议,使用ssl 协议作为会话层协议,这里通过这篇文章结合抓包来看一下具体过程

About SSL / TLS

这个协议最早是由网景公司 开发,但是随着网景的没落,现在由ietf负责维护,最初的版本也已经重新冠名(re-banded)tls(安全传输层协议) 1.0(1999年)。因此现在大部分协议是基于TLS的,尽管是相似的东西。

https 建立简介过程

client say hello

  • 客户端浏览器发起握手请求,在ssl 协议头的 content type 设置为 handshake(0x16)。这表明这是一个handshake record。
  • 紧接着的2字节是ssl 的版本号。
  • 整个handshake 内容又分为几个部分的消息

    • Random 4字节的unix时间格式的 UTC时间(协调世界时),后面紧跟28 bit 的随机数。这个将在后面用到
    • Session ID , 这个在client hello 阶段是空,假设我们之前已经与服务端建立过https 链接,那么这个有可能是一个有意义的数字
    • Cipher Suites 这里给出了所有浏览器支持的加密协议,最顶部的是浏览器最期望使用的协议。
    • server_name extension 这里给出客户端正尝试访问的URL。因为ssl发生在http建立连接之前。而服务器可能是一个ip对应多个URL的方式,这个时候是无法区分对应的服务的。(nginx的 TLS NSI 支持)

      LVS使用FULLNAT模式,每台Nginx 机器只有一个IP(内网IP),LVS也是把流量转到这个IP。如果Nginx想对多个域名使用https,比如两个域名 wandoujia.com 和 wandoulabs.com ,是可能有问题的。

      事实上,SSL运行在TCP之上(SSL/TLS协议),ssl通过四次握手 和服务器(这里是Nginx,LVS纯转发,可忽略)的IP + PORT(443)建立ssl连接,建立连接之后浏览器才会发送HTTP请求。所以在Nginx收到HTTP请求之后才知道Host,才知道转到哪个server 去处理,所以在SSL连接建立的时候Nginx是不知道用哪个 Server 的SSL配置的,在这种情况下,Nginx会使用它加载到的第一个SSL配置(需验证)。

      那么怎么才能实现多域名的 https 呢,是有办法的,叫做 TLS Server Name Indication extension(SNI, RFC 6066),它允许浏览器在SSL握手的时候发送请求的server name,也就是 Host,这样 Nginx 就能找到对应server 的SSL配置。

server hello

server 回复客户端 hello 包含2个packet 2551字节的回复,包含tls 版本信息。整个server hello 可以分为3部分消

  • server hello message : 
    • 4byte Unix UTC 时间 和 28 byte 的随机数
    • 32 字节session ID, 用于避免完下次全握手
    • 服务端提供的 加密套件。例如: (0x0004)TLS_RSA_WITH_RC4_128_MD5,这代表着 RSA 公钥算法、RC4加密算法、MD5 hash认证函数,
  • Cerfificate Message : 证书消息,客户端用于认证server 的证书
  • Server Hello Done 通知client hello done,server 不会要求client 的证书

Checking out the Certificate & Verifying Signatures

  • 客户端需要验证server 的证书有效性,来确认是否应该信任 server。首先确认证书尚未过期,同时确认 证书的公钥是授权的,可以用于私钥交换。防止发成 中间人攻击

    because we are implicitly trusting that the people on the certificate trust chain wouldn’t do something bad, like sign a certificate claiming to be from Amazon.com unless it actually was Amazon.com. If an attacker is able to modify your DNS server by using a technique like DNS cache poisoning, you might be fooled into thinking you’re at a trusted site (like Amazon.com) because the address bar will look normal. This last check implicitly trusts certificate authorities to stop these bad things from happening.

    简单地说就是,我们的密钥交换过程应该是发生在信任的通道中,如果不是这样,比如,有人你与服务器之间,欺骗你与他建立了信任关系(劫持dns 等等方式)。那么你的认证就是去了意义。因此引入三方认证,避免这种可能性。

  • 紧接着要说的是浏览器 如何 验证证书的合法性

    如果不能保证证书是server 的合法证书,那么客户端发送的信息就有可能存在被窃听的危险,因为用此公钥加密的数据可以被其对应的私钥拥有者获取,而该私钥并不在客户端所认为的服务器上。 
    因此可采用一个权威机构进行证书的颁发,所谓证书就是包含了服务器声明的公钥以及组织名称等信息,这里我们只考虑最关键的公钥信息。该权威机构会对申请证书的组织进行审核,确保其身份合法,然后将服务器公钥信息发布给客户端,客户端可利用该公钥与对应的服务器进行通信。整个过程可归纳为以下几步:

    1、服务器生成一对密钥,私钥自己留着,公钥交给数字证书认证机构(CA)

    2、CA进行审核,并用CA自己的私钥对服务器提供的公钥进行签名(参照上文RSA签名)

    3、客户端从CA获取证书(即服务器端公钥),用CA的公钥对签名的证书进行验证,比对一致,说明该服务器公钥确实是CA颁发的(得此结论有一个前提就是:客户端的CA公钥确实是CA的公钥,即该CA的公钥与CA对证书进行签名的私钥确实是一对。参照上文RSA签名中所论述的情况),而CA又作为权威机构保证该公钥的确是服务器端提供的,从而可以确认该证书中的公钥确实是合法服务器端提供的

    注:为保证第3步中提到的前提条件,CA的公钥必须要安全地转交给客户端,因此,CA的公钥一般来说由浏览器开发商内置在浏览器的内部。于是,该前提条件在各种信任机制上,基本保证成立。

整个过程涉及2对公私密钥对,一对由服务器产生,用于加密,一对由CA产生,用于签名。 
整个过程还涉及2个信任:客户端信任CA,CA发布的证书中的公钥就是合法服务器的公钥。客户端信任浏览器内置的CA公钥就是与CA私钥对应的公钥。

验证正式是否吊销可以采用黑名单方式或者OCSP方式。黑名单(CRL)就是定期从CA下载一个名单列表,里面有吊销的证书序列号,自己在本地比对一下就行。优点是效率高。缺点是不实时。OCSP是实时连接CA去验证,优点是实时,缺点是效率不高。

OCSP 全称在线证书状态检查协议 (rfc6960),用来向 CA 站点查询证书状态,比如是否撤销。 通常情况下,浏览器使用 OCSP 协议发起查询请求,CA 返回证书状态内容,然后浏览器接受证书是否可信的状态。因此如果 server 将证书保存下来,浏览器请求时候直接通过自己的服务器发送回去,防止验证服务器出问题,还能加快访问速度。

Pre-Master Secret

到目前为止,我们已经认证了server 并且获得了server 的可信任公钥和加密方式(?),但是此时,窃听者也可以获得我们我们一样多的信息。所以我们需要创建一个随机密钥,然而这并不容易

In 1996, researchers figured out that Netscape Navigator 1.1 was using only three sources to seed their pseudo-random number generator (PRNG). The sources were: the time of day, the process id, and the parent process id. As the researchers showed, these “random” sources aren’t that random and were relatively easy to figure out.

早在1996年,研究人员就发现网景浏览器1.1 版本使用的3个随机数种子 非常容易被破解,因此所谓的“随机密钥”其实并不随机,容易被伪造

生成的48位pre master secret随机值 ,前两位是ssl 版本

Trading Secrets

客户端采用server通知的加密方式(服务端经过验证的公钥)加密pre master secret 并发送给server,这里还要通过填充随机数,把premaster 扩充到128 位(根据协议)

we should pad these bytes with random data to make the input equal to exactly the size of the modulus (1024 bits/128 bytes).

  • 客户端通知server client key exchange 发送密钥
  • 客户端通知server Change Cipher Spec,这个是最后一条未加密的消息

Deriving the Master Secret

现在客户端(浏览器)有了3个随机值,我们的random 、server 的random 、我们生成的premaster,这三个值虽然都是伪随机,但是合并在一起,就十分的接近随机了。通过这3个值,我们就可以获取到一个 随机密钥,用于对称加密

master_secret = PRF(pre_master_secret, “master secret”, ClientHello.random + ServerHello.random)

到这里,client 和 server就都有了一个master secret可以用于加密。

Generating Keys

到这里,我们还需要生成一些key 用于加密的过程。

根据加密方式的不同,可能生成的这些附加key 也不相同。比如,如果是块加密,那么我们还需要生成IV,如果是非流式加密就不需要

Prepare to be Encrypted

客户端发送finished message,包含一个含有收到的全部握手信息的校验值(12字节)。并且在头部加入0x14 表示 finish、 0x00 0x00 0x0c 表示12字节

verify_data = PRF(master_secret, “client finished”, MD5(handshake_messages) + SHA-1(handshake_messages) )

server同样的方式相应client,并且验证client。

在这之后握手过程就结束了,可以进入应用层的 加密的 http 服务了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值