Skip to content

Latest commit

 

History

History
392 lines (184 loc) · 18.4 KB

12.HTTPS.md

File metadata and controls

392 lines (184 loc) · 18.4 KB
title date categories tags description
HTTPS
2019-06-11
Git
Git

from:https://zhuanlan.zhihu.com/p/36981565

from:https://zhuanlan.zhihu.com/p/25976060

HTTPS

HTTP 通讯数据明文传输,速度快;

HTTPS 通讯数据加密传输,但是速度可能会稍微慢一点.

HTTPS中的S表示SSL或者TLS,就是在原HTTP的基础上加上一层用于数据加密、解密、身份认证的安全层。

如上图所示 HTTPS 相比 HTTP 多了一层 SSL/TLS。原先是应用层将数据直接给到TCP进行传输,现在改成应用层将数据给到TLS/SSL,将数据加密后,再给到TCP进行传输。

SSL(Secure Socket Layer,安全套接字层):1994年为 Netscape 所研发,SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。

TLS(Transport Layer Security,传输层安全):其前身是 SSL,它最初的几个版本(SSL 1.0、SSL 2.0、SSL 3.0)由网景公司开发,1999年从 3.1 开始被 IETF 标准化并改名,发展至今已经有 TLS 1.0、TLS 1.1、TLS 1.2 三个版本。SSL3.0和TLS1.0由于存在安全漏洞,已经很少被使用到。TLS 1.3 改动会比较大,目前还在草案阶段,目前使用最广泛的是TLS 1.1、TLS 1.2。

第一层(安全传输数据)

假如我们要实现一个功能:一个用户A给一个用户B发消息,但是要保证这个消息的内容只能被A和B知道,其他的无论是墨渊上神还是太上老君都没办法破解或者篡改消息的内容。

如上图,需求就是这么简单,A给B发一条消息,因为比较私密,不想被其他人看到。

由于消息不想被其他人看到,所以我们自然而然就会想到为消息加密,并且只有A和B才有解密的密钥。这里需要考虑几点:

  1. 使用什么加密方式?
  2. 密钥怎么告知对方?

对于第一个问题(加密方式),加密算法分为两类:对称加密和非对称加密,这里我们选择对称加密,原因有如下几个:

  1. 对称加密速度快,加密时CPU资源消耗少;
  2. 非对称加密对待加密的数据的长度有比较严格的要求,不能太长,但是实际中消息可能会很长(比如你给你女朋友发情书),因此非对称加密就满足不了;

对于第二个问题(密钥怎么告知对方),这是导致整个HTTPS通信过程很复杂的根本原因。 如果A或B直接把他们之间用于解密的密钥通过互联网传输给对方,那一旦密钥被第三者劫持,第三者就能正确解密A,B之间的通信数据。

第二层(安全传输密钥)

通过第一层的描述,第二层需要解决的问题是:安全地传输A,B之间用于解密数据的密钥。

因为如果传输过程中这把密钥被第三者拿到了,就能解密传通信数据,所以,这把密钥必须得加密,就算第三者劫持到这把加密过的密钥,他也不能解密,得到真正的密钥。

这里有一个问题,那要用什么方式加密这把密钥呢?如果使用对称加密,那这个对称加密的密钥又怎么安全地告诉对方呢?完了,陷入死循环了.... 所以,一定不能用对称加密。

那就是用非对称加密咯

考虑如下方式:

  1. 客户端: 我要发起HTTPS请求,麻烦给我一个非对称加密的公钥;

    非对称加密,公钥加密,私钥解密

  2. 服务器: (生成一对非对称加密的密钥对,然后把公钥发给客户端),接着,这是公钥;

  3. 客户端:(收到公钥,生成一个随机数,这个随机数是后续使用对称加密对传输内容加密的真正的密钥,用刚才收到的公钥加密这个密钥,然后发给服务器)这是我刚生成的加密过的密钥;

  4. 服务器:(收到加密后的密钥,用本地的第一步自己生成的非对称加密的私钥解密,得到真正的密钥);

  5. 现在,客户端和服务器都知道了这把密钥,就能愉快地用这个密钥对称加密数据...

可行性分析:

  • 上述步骤中最终用于加密数据的密钥是客户端生成的(就是那个随机数),并且用公钥加密之后传给服务器的,因为私钥只有服务器才有,所以也就只有服务器才能解开客户端上报的密钥;如果这个加密后的随机数被坏人窃取了,也没事,因为坏人没有服务器的那个私钥,坏人解不开,所以坏人就拿不到真正的密钥。
  • 要保证传输的密钥只能被服务器解密,就得保证用于加密密钥的公钥一定是服务器下发的,绝对不可能被第三方篡改过;

因为还可能存在一种"中间人攻击"的情况,如下图:

第三层(安全传输公钥)

从上一层可以知道,要保证数据的安全,就必须得保证服务器给客户端下发的公钥是真正的公钥,而不是中间人伪造的公钥。那怎么保证呢?

那就得引入数字证书了,数字证书是服务器主动去权威机构申请的,证书中包含了 服务器生成的A公钥(被权威机构的私钥加密过)、权威机构的信息、域名等相关信息。所以服务器只需要给客户端下发数字证书即可。现在流程图如下:

那数字证书中的A公钥是如何加密的呢?

答案是非对称加密,只不过这里是使用只有权威机构自己才有的私钥加密。(私钥加密,其实是签名)

等一下,既然A公钥被权威机构的私钥加密了,那客户端收到证书之后怎么解密证书中的A公钥呢?需要有权威机构的公钥才能解密啊!那这个权威机构的公钥又是怎么安全地传输给客户端的呢?感觉进入了鸡生蛋,蛋生鸡的悖论了~~

别慌,**答案是权威机构的公钥不需要传输,因为权威机构会和主流的浏览器或操作系统合作,将他们的公钥内置在浏览器或操作系统环境中。**客户端收到证书之后,只需要从证书中找到权威机构的信息,并从本地环境中查询找到权威机构的公钥,就能正确解密A公钥。(公钥解密,其实说的是验证)

这样就绝对安全了吗?既然权威机构能给服务器签发数字证书,那为什么就不可能给中间人(坏人)签发数字证书呢?毕竟赚钱的生意权威机构也不会拒绝的呀。

试想一下:

前提:权威机构给服务器和中间人(坏人)都颁发了数字证书。

服务器给客户端下发数字证书时证书被中间人劫持了,中间人将服务器的证书替换成自己的证书下发给客户端,客户端收到之后能够通过权威机构的公钥解密证书内容(因为中间人的证书也是权威机构私钥加密的),从而获取公钥,但是,这里的公钥并不是服务器原本的A公钥,而是中间人自己证书中的B公钥。从第二层可知,如果不能保证客户端收到的公钥是服务器下发的,那整个通信数据的安全就没法保证。简单总结就是证书被调包~

所以,还得保证客户端收到的证书就是服务器下发的证书,没有被中间人篡改过。

第四层(安全传输证书)

这是最后一层了,这一层,我们的任务是:保证客户端收到的证书是服务器下发的证书,没有被中间人篡改过。

所以,这里就有两个需求:

  • 证明证书内容没有被第三方篡改过;
  • 证明证书是服务器下发的;

其实这些问题,数字证书本身已经提供方案了,数字证书中除了包含加密之后的服务器公钥,权威机构的信息之外,还包含了证书内容的签名(先通过Hash函数计算得到证书数字摘要,然后用权威机构私钥加密数字摘要得到数字签名),签名计算方法以及证书对应的域名。

这样一来,客户端收到证书之后:

  • 使用权威机构的公钥解密数字证书,得到证书内容(服务器的公钥)以及证书的数字签名(权威机构用自己的私钥签名过的),(这里应该还要用权威机构的公钥再对签名解密一下,才能拿到原数据,原数据就是证书的Hash值),然后根据证书上描述的计算证书签名的方法计算一下当前证书的签名(应该不是签名,而是证书Hash值),与收到的签名(应该是与解密出来的那个Hash值)作对比,如果一样,表示证书一定是服务器下发的,没有被中间人篡改过。因为中间人虽然有权威机构的公钥,能够解析证书内容并篡改,但是篡改完成之后中间人需要将证书重新加密,但是中间人没有权威机构的私钥,无法加密,强行加密只会导致客户端无法解密,如果中间人强行乱修改证书,就会导致证书内容和证书签名不匹配。所以证书签名就能判断证书是否被篡改

    签名:说的是私钥加密,然后通过公钥解密。这样可以确定来源。因为只有持有私钥的那个人签名过的才能被正确的解密。

  • 再考虑证书被掉包的情况:中间人同样可以向权威机构申请一份证书,然后在服务器给客户端下发证书的时候劫持原证书,将自己的假证书下发给客户端,客户端收到之后依然能够使用权威机构的公钥解密证书,并且证书签名也没问题。但是这个时候客户端还需要检查证书中的域名和当前访问的域名是否一致。如果不一致,会发出警告!(比如我们想访问自己的服务器ewell.cc,证书中的域名与我们访问的自己服务器的域名不一样,很可能就是证书被掉包了)

从上面的分析可以看到,数字证书中的信息确实能让客户端辨别证书的真伪。

客户端在接受到服务端发来的SSL证书时,会对证书的真伪进行校验

以浏览器为例说明如下:

(1)首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验

(2)浏览器开始查找操作系统中已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发

(3)如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。

(4)如果找到,那么浏览器就会从操作系统中取出 颁发者CA 的公钥,然后对服务器发来的证书里面的签名进行解密

(5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值(应是各种信息整合在一起,计算出来的hash值,还是证书文件的hash??),将这个计算的hash值与证书中签名解密后的值做对比

(6)对比结果一致,则证明服务器发来的证书合法,没有被冒充

(7)此时浏览器就可以读取证书中的公钥,用于后续加密了

非对称加密中间人攻击

本来A 和 B 使用各自的私钥+公钥进行加密通信,挺好。

现在C 来中间拦截。

*实际使用*

非对称加密算法比对称加密算法要复杂的多,处理起来也要慢得多。如果所有的网络数据都用非对称加密算法来加密,那效率会很低。所以在实际中,非对称加密只会用来传递一条信息,那就是用于对称加密的密钥。当用于对称加密的密钥确定了,A和B还是通过对称加密算法进行网络通信。这样,既保证了网络通信的安全性,又不影响效率,A和B也不用见面商量密钥了。

所以,在现代,A和B之间要进行安全,省心的网络通信,需要经过以下几个步骤

  • 通过CA体系交换public key
  • 通过非对称加密算法,交换用于对称加密的密钥
  • 通过对称加密算法,加密正常的网络通信

这基本就是SSL/TLS的工作过程了。

这里要注意区分 服务器公钥、私钥 和 权威机构(CA)公钥、私钥

服务器公钥和私钥是服务器自己生成的,并且去权威机构申请证书的时候,要把服务器公钥告诉机构,因为机构要把服务器公钥放在证书里面加密的。

权威机构的私钥,只有他自己有,别人不可能拿到。权威机构的公钥,是公开的,在浏览器或者操作系统里就能拿到的

HTTPS 工作过程

*HTTPS*

HTTPS全称是HTTP over SSL,也就是通过SSL/TLS加密HTTP数据,这或许是SSL最广泛的应用。

前面提到了CA作为一个公证机构,能确保数字证书的真实性。但是在实际使用中,CA认证一般是要收费的,普通人不会去做CA认证,进而获得属于自己的数字证书。更多的是,一些大的机构,例如银行,网店,金融机构,它们去获得自己的数字证书。那这种情况如何保证网络通信的安全呢?

这些机构获取到CA授予的数字证书之后,将数字证书加到自己的web服务器上。当用户要去访问它们的网页,例如https://domain.com,会经过下图所示的步骤。与上面的图其实是一致的

  • 用户向web服务器发起一个安全连接的请求

  • 服务器返回经过CA认证的数字证书,证书里面包含了服务器的public key

  • 用户拿到数字证书,用自己浏览器内置的CA证书公钥解密得到服务器的public key

  • 用户用服务器的public key加密一个用于接下来的对称加密算法的密钥,传给web服务器

    • 因为只有服务器有private key可以解密,所以不用担心中间人拦截这个加密的密钥
  • 服务器拿到这个加密的密钥,使用服务器的私钥解密获取密钥,再使用对称加密算法,和用户完成接下来的网络通信

现在用户知道自己访问的网站是正规的网站,否则用户浏览器会报错说不能用CA证书解析。服务器通过CA授予的数字证书自证了身份。

但,这里的安全隐患在于,服务器怎么知道访问者就是真用户呢?之前介绍的双向认证是可以通过数字证书验明用户的正身,现在用户为了省钱没有数字证书。这种情况下一般是通过用户名密码来确认用户。所以,大家要保管好自己的密码。

客户端想要确认服务器是可信的,就用HTTPS

服务器想要确认客户端是可信的,就用账号密码,或者带token

看下CA 证书里面的内容:

1. 证书版本号(Version)
    版本号指明X.509证书的格式版本现在的值可以为:
        1) 0: v1
        2) 1: v2
        3) 2: v3
    也为将来的版本进行了预定义

2. 证书序列号(Serial Number)
    序列号指定由CA分配给证书的唯一的数字型标识符”。当证书被取消时实际上是将此证书的序列号放入由CA签发的CRL中这也是序列号唯一的原因3. 签名算法标识符(Signature Algorithm)
    签名算法标识用来指定由CA签发证书时所使用的签名算法”。算法标识符用来指定CA签发证书时所使用的:
        1) 公开密钥算法
        2) hash算法
    example: sha256WithRSAEncryption
    须向国际知名标准组织(如ISO)注册

4. 签发机构名(Issuer)
    此域用来标识签发证书的CA的X.500 DN(DN-Distinguished Name)名字包括:
        1) 国家(C)
        2) 省市(ST)
        3) 地区(L)
        4) 组织机构(O)
        5) 单位部门(OU)
        6) 通用名(CN)
        7) 邮箱地址

5. 有效期(Validity)
    指定证书的有效期包括:
        1) 证书开始生效的日期时间
        2) 证书失效的日期和时间
    每次使用证书时需要检查证书是否在有效期内6. 证书用户名(Subject)
    指定证书持有者的X.500唯一名字包括:
        1) 国家(C)
        2) 省市(ST)
        3) 地区(L)
        4) 组织机构(O)
        5) 单位部门(OU)
        6) 通用名(CN)
        7) 邮箱地址

7. 证书持有者公开密钥信息(Subject Public Key Info)
    证书持有者公开密钥信息域包含两个重要信息:
        1) 证书持有者的公开密钥的值
        2) 公开密钥使用的算法标识符此标识符包含公开密钥算法和hash算法8. 扩展项(extension)
    X.509 V3证书是在v2的基础上一标准形式或普通形式增加了扩展项以使证书能够附带额外信息标准扩展是指
    由X.509 V3版本定义的对V2版本增加的具有广泛应用前景的扩展项任何人都可以向一些权威机构如ISO
    注册一些其他扩展如果这些扩展项应用广泛也许以后会成为标准扩展项9. 签发者唯一标识符(Issuer Unique Identifier)
    签发者唯一标识符在第2版加入证书定义中此域用在当同一个X.500名字用于多个认证机构时用一比特字符串
    来唯一标识签发者的X.500名字可选10. 证书持有者唯一标识符(Subject Unique Identifier)
    持有证书者唯一标识符在第2版的标准中加入X.509证书定义此域用在当同一个X.500名字用于多个证书持有者时用一比特字符串来唯一标识证书持有者的X.500名字可选11. 签名算法(Signature Algorithm)
    证书签发机构对证书上述内容的签名算法
    example: sha256WithRSAEncryption

12. 签名值(Issuers Signature)
    证书签发机构对证书上述内容的签名值