彻底吃透 TLS/SSL

TLS/SLL 是如今网络安全通讯比较重要的一环,经过一些列的 key 交换和 key 生成,最终确立加密通道的整个流程。众所周知,TLS/SSL 耗费的时间也是挺可观的,相对于 TCP 的3次 RTT 来讲,若是加上 TLS/SSL, 则总的 RTT 时间至少为 4 次。虽然看起来不少,但若是相对于如今的网络环境来讲,大概也就每次 20~30ms,这样算下来,估计也就 100ms 左右。这样的时间差仍是能够忍受的,不过,这里还没算入 DNS 解析,这个暂时不考虑。并且,TLS/SSL 生成的 sessionkey 若是在有效期内的话,那么这个时间就能够彻底忽略掉了。很少说了,咱们直接来看下 TLS/SSL 的基本内容。html

文章摘自: please call me HRlinux

TLS 算法

TLS/SSL 其实就是经过非对称加密,生成对称加密的 sessionkey 的过程。对称加密的算法无外乎就 AES,或者使用 Cipher/Decipher 模块。而非对称加密经常使用的就是 RSA,不过也有使用 Diffie-Hellman (迪菲)。但,较安全性来讲,DH 要高一些。由于,RSA 在生成 sessionkey 时,最后是由 browser 生成,而后经过 public key 加密后传给 server 的,这样存在必定的问题是,若是 hacker 获得了 private key,那么,他能够全程监控流量,而后使用 private key 进行解密,那么可想而知,sessionkey 也就暴露了。 但对于 DH 来讲,它机制的不一样点在于,sessionkey 不会经过网络传输,而是在两端独立生成的。ok~ 这就涉及到两个 key 的一致性问题。DH 还有一个机制,即,前向安全性(perfect forward secrecy--PFS):server 端的 private key,不能用来代替之前任何一把的 sessionkey,因此,也没法破解之前任何一次的 session 内容。每次链接,DH 都会从新生成一个 key,而且当该次 session 结束时,丢弃它。不过,这并非很大的问题,由于 DH 能很快的生成 key。由于它耗费在网络上的时间相比于 RSA 来讲少了一半。能够从下图简单了解 DH 的加密算法:nginx

DH

简单来讲,两边经过一次的信息交换,完成了密钥生成。由于 sessionkey 是独立放在两端的,为了达到一致性,每次链接时,DH 都须要从新协商生成 sessionkey。如今有个问题是: 为何必定要有 session key,他存在的意义是什么?git

sessionkey 用途

TLS/SSL 其实就是经过非对称加密,生成对称加密的 session key 的过程程序员

那 session key 主要又干了什么呢? 首先,咱们要先明确,session key 是用来进行对称加密的,这种加密方式主要使用到的是 AES 加密算法。这不一样于 Elliptic Curve Diffie-Hellman (ECDH) 这种非对称加密算法。二者其实均可以用来对信息进行加密,但因为算法内部的实现机理不一样,他们所用的时间也是不同的。基本上是,ECDH 所用的时间是 AES 的 3 倍。github

你能够自行测试一下:算法

openssl speed ecdh
openssl speed aes
复制代码

ok,上面大概简述了 TLS/SSL 所用到的算法。接下来,咱们来了解一下,具体 TLS/SSL 密钥交换的过程。浏览器

TLS/SLL 过程

在详述过程以前,咱们须要了解一下,在过程当中会出现的内容。缓存

  • session key: 这是 TLS/SSL 最后协商的结果,用来进行对称加密。
  • client random: 是一个 32B 的序列值,每次链接来时,都会动态生成,即,每次链接生成的值都不会同样。由于,他包含了 4B 的时间戳和 28B 的随机数。
  • server random: 和 client random 同样,只是是由 server 端生成。
  • premaster secret: 这是 48B 的 blob 数据。它能和 client & server random 经过 pseudorandom (PRF) 一块儿生成 session key。
  • cipher suite: 用来定义 TLS 链接用到的算法。一般有 4 部分:
    • 非对称加密 (ECDH 或 RSA)
    • 证书验证 (证书的类型)
    • 保密性 (对称加密算法)
    • 数据完整性 (产生 hash 的函数) 好比 AES128-SHA 表明着:
      • RSA 算法进行非对称加密
      • RSA 进行证书验证
      • 128bit AES 对称加密
      • 160bit SHA 数据加密算法
    • 好比 ECDHE-ECDSA-AES256-GCM-SHA384 表明着
      • ECDHE 算法进行非对称加密
      • ECDSA 进行证书验证
      • 265bit AES 对称加密
      • 384bit SHA 数据加密算法

相信你们对这张图已经很熟悉了:安全

TLS/SSL

不过,上面不是说了有两种不一样的非对称加密方式吗? RSA & DH? 那为何图只是一个嘞? ok,实际上这图没错,他并无把传输的内容是什么写出来,这很关键。而两种算法也是在传输内容上区分开的,基本的过程是彻底同样的。根据 wiki 的解释,咱们大概能知道整个传输过程须要的内容。

tls/ssl

  1. 客户端发送 clientHello 信息,包含了客户端支持的最高 TLS 协议版本,random num (上文提到过),cipher suite。若是,客户端使用 resumed handshake,那么这里发送的就是 sessionID。若是,客户端还支持 ALPN,那么它应该还须要发送它所支持的其余协议,好比 HTTP/2.
  2. 在 server 端进行 serverhello 阶段,这里 server 根据 client 发送过来的相关信息,采起不一样的策略,一样会发送和 client 端匹配的 TLS 最高版本信息,cipher suite 和 本身产生的 random num. 而且,这里会产生该次链接独一无二的 sessionID
  3. 经过 certificate 阶段,会在信息流中加入 public key certification。ServerKeyExchange 该阶段,主要是针对于 ECDH 加密方式,这里就不赘述,后面再进行讲解。
  4. serverHelloDone 标识这 server 阶段处理结束,将该阶段产生的信息发送给 client。
  5. 在 clientKeyExchange 阶段时,client 会随机生成一串 pre-master secret 序列,而且会经由 public key 加密,而后发送给 server。在 ChangeCipherSpec 阶段,主要是 client 本身,经过 pre-master secret + server random-num + client random-num 生成 sessionKey。这就标识着,此时在 client 端,TLS/SSL 过程已经接近尾声。
  6. 后面在 server 端进行的 ChangeCipherSpec 和 client 进行的差很少,经过使用 private key 解密 client 传过来的 pre-master secret ,而后生成 sessionkey。 后面再经过一次验证,使用 session Key 加密 server finshed,发送给 client,观察可以成功解密,来表示最终的 TLS/SSL 完成。

上面主要是根据 RSA 加密方式来说解的。由于 RSA 才会在 TLS/SSL 过程当中,将 pre-master secret 显示的进行传输,这样的结果有可能形成,hacker 拿到了 private key 那么他也能够生成如出一辙的 sessionKey。即,该次链接的安全性就没了。

接下来,咱们主要讲解一下另一种加密方式 DH。它和 RSA 的主要区别就是,到底传不传 pre-master secret。RSA 传而 DH 不传。

根据 cloudflare 的讲解能够清楚的了解到二者的区别:

这是 RSA 的传输方式,基本过程如上述。

RSA

而 DH 具体区别在下图:

DH_TLS/SSL

这里先补充一下 DH 算法的知识。由于,pre-master secret 就是根据这个生成的。DH 基本过程也不算太难,详情能够参考 wiki。 它主要运用到的公式就是:

DH_algorithm

为了防止在 DH 参数交换时,数据过大,DH 使用的是取模数的方式,这样就能限制传输的值永远在 [1,p-1]。这里,先说明一下 DH 算法的基本条件:

  • 公共条件: p 和 g 都是已知,而且公开。即,第三方也能够随便获取到。
  • 私有条件: a 和 b 是两端本身生成的,第三方获取不到。

基本流程就是:

DH_algo

咱们只要把上图的 DH parameter 替换为相对应的 X/Y 便可。而最后的 Z 就是咱们想要的 Premaster secret。 以后,就和 RSA 加密算法一致,加上两边的 random-num 生成 sessionKey。经过,咱们经常称 DH 也叫做 Ephemeral Diffie-Hellman handshake。 由于,他每次一的 sessionKey 都是不一样的。

而 RSA 和 DH 二者之间的具体的区别就在于:RSA 会将 premaster secret 显示的传输,这样有可能会形成私钥泄露引发的安全问题。而 DH 不会将 premaster secret 显示的传输。

TLS/SSL 中的基本概念

上面内容大概讲清楚了基本的 TLS/SSL 的加密过程。不过,其中,还有不少其余的小细节,好比 SNI,ALPN,Forward Secrey。 接下来,咱们主要将这些细节将一下,由于他们其实也很重要。

Forward Secrey

FS(Forward Secrey) 主要是针对 private key 进行描述了。若是你的 private key 可以用来破解之前通讯的 session 内容,好比,经过 private key 破解你的 premaster secret ,获得了 sessionKey,就能够解密传输内容了。这种状况就是 non-forward-secrey。那如何作到 FS 呢? 很简单,上文也已经提到过了,使用 DH 加密方式便可。由于,最后生成的 sessionKey 和 private key 并无直接关系,premaster secret 是经过 g(ab) mod P 获得的。

简单的说就是,若是你想要启用 FS,那么你应该使用的是 DH 加密方式,而放弃 RSA。不过,因为历史缘由(TLS 版本问题),RSA 如今还算是主流的加密方式。但,DH 也凭借他 5S 的安全性,份额也在增长。

ALPN

ALPN 全称是 Application Layer Protocol Negotiation(应用层协议协商机制)。看到应用层,程序员们应该都能反应出 OSI 7层网络协议。在应用层中,HTTP 协议应该是重点。不过,因为 HTTP 版本的问题,以及如今 HTTP2 的流行,为了让 client-server 使用相同的协议而出现了 ALPN。ALPN 其实是从 SPDY 中的 NPN 协议衍生出来的。不过,它们俩的机制正好相反。

  • NPN: 由 server 端告诉 client,它支持什么协议,而后 client 确认支持的协议后,开始进行链接。
  • ALPN:在 TLS 阶段,由 client 告诉 server,它所支持的全部协议,而后开始进行链接。

总的来讲,NPN 已经退出历史的舞台了。。。ALPN 如今是 IETF 指定的标准协议。ALPN 在 TLS 具体的过程是:

  • 在 clientHello 阶段,client 会在 message 中,添加一个 ProtocolNameList 字段。用来表示它所支持的协议列表
  • server 端在 serverHello 阶段,处理 client 提供的 ProtocolNameList。而且选择最高版本的协议,执行。将选择信息添加到 serverhello 内。

SNI

SNI 的全称为:Server Name Indication。该机制的提出的意义是,当有一个 server 同时处理了不少个 host 时。至关于,一个 IP 映射多个域名,但,因为证书只能对一个 3 级域名有效,因此,针对于多个 host 来讲,server 为了能同时兼顾这些域名。一种简单的办法就是重定向到指定域名,若是都想支持的话,也行,掏钱本身多买几个证书 (真土豪)。若是,你很土豪的话,如今就有这样的状况,一个 IP 服务器下,搭载了支持多个域名的 server,而且每一个域名都有合法的 CA 证书。那么,server 怎么判断,哪个域名用哪个证书呢?这时候,就须要用到 SNI。至关于在 TLS 阶段,将 host 一并发送过去,而后 server 就知道在 serverhello 阶段该返回啥证书了。 如今,有个问题,为何必定要用 SNI 呢? 咱们回想一下,这里咱们仅仅只是创建 TCP + TLS 链接,客户端的一些内容,好比 hostname,咱们并不能在 TCP 中得到。而,想要得到的话,就须要等到 HTTP 阶段,得到 client 传过来的 hostorigin 字段。因此,为了解决这个比较尴尬的点,就提出了 SNI。

Session Resumption

感受能看到这里的人,应该都是闲的蛋疼的人。。。若是让我来看这篇文章,估计看几张图,我基本上就直接关网站了。由于,这实在是复杂。而且,上面说的只是协议上的复杂性,对于计算机来讲,只须要记下每一次该发什么东西而已,但真正让 Computer 感到蛋疼的是,key 的计算。特别是 random key 和 premaster secret 动不动就是 32B,48B 的数据量。因此,为了真正减小计算机的工做量(其实是 server),提出了 Session ID 和 Session Tickets,来将成功进行链接的 session 内容缓存起来。

Session ID

Session ID 是 server 将上一次成功链接的 session 内容存在本身的硬盘里面。这里,就不涉及对 session data 的二次加密。基本的过程是:

  1. client 端在 clientHello 阶段,将 random num,TLS protocol 和经过 hostname 匹配到的最新一次的 session ID 发送给 server 端。(也就是说,client 一样须要存储一份 session data)
  2. server 接收到 session ID 后,在缓存中查找,若是找到,则直接进行 ChangeCipher 阶段,开始生成sessionKey。而后,返回相同的 sessionID 便可。

那么相对于彻底的 TLS/SSL 链接来讲,这里只用到了一次 RTT。那么协议过程就变为了:

session Resumption

Session Ticket

既然 Session ID 是为了解决网络时延和计算机性能问题,那么 Session Ticket 又干了什么呢? Session Ticket 和 Session ID 作的也是一样的事情,server 将最新一次的 sesion data 经过二次加密,在上一次握手结束时传递过去,而后 client 将传递过来的信息保存。 这样,利不利用缓存的 session data 这时,就取决于 client。若是该次的 session data 没有过时,那么 client 就会在 clientHello 阶段将该数据发送过去,server 接受到以后,便开始进行解密而后,双方生成 sessionKey,握手结束。 那 Session Ticket 和 Session ID 到底用哪个呢? 这估计得看你的业务状况了,Session ID 注重的是节省性能,而损耗部分空间。Session Ticket 注重的是节省空间,而损耗部分性能。它们二者都能节省一次 RTT 时间,用谁,仍是得看你的服务器的具体状况。

CA 证书详情

前面大体说了 TLS/SSL 是怎样运做的,以及有哪些链接方法。至关于,学画一条线同样,咱们如今只知道这条线该画多长,但还不知道,这条线从哪里画。因此,接下来,咱们就须要来探讨一下,两端发生了什么。其实也不难,主要仍是关于 CA 证书的存放和验证。server 端的很简单,就是把本身的 CA 证书发过来就 ok。但,client 验证这个证书是否可信,会有点复杂。 首先,证书颁发机构就那么一些,换句话理解就是,每一个证书颁发机构,就表明着一张 CA 证书。但,如今市面上的 HTTPS 网站,辣么辣么多,难道他们都用同一张证书?难道他们都有同样的 pu/pr key? 那么 HTTPS 安全还有用吗? 因此,按照上面的推理,咱们的网站上的 HTTPS 证书,确定都是各不同的。通常来讲,有 3 种类型的证书: DV(Domain Validation),OV(Organization Validation),EV(Extended Validation)。均价按照顺序上升,因此,最便宜的就是 DV,这应该是咱们勤劳的贫苦大众用得起的。它们之间具体的区别在于域名的支持上:

  • DV:就是我的证书嘛,基本支持的就是单域名和多域名,不支持泛域名(*.villainhr.com)。不过,看价格,好比我这个就是腾讯云给的一个免费的 DV 证书,因此,就支持一个 3 级域名(https://www.villainhr.com)。若是是收费的,单/多域名应该都支持。
  • OV:就比较牛逼,面向企业的,多域名/泛域名都支持。
  • EV:属于贵族用的,通常人也搞不到,主要它还须要去买个保险。。。

那咱们的证书在芸芸证书中,是处于哪个层级呢? 通常是三级。怎么体现的呢?

certificate

那这么多证书,咱们用的是哪个呢?固然是,最下面那个。由于每一个证书并非都被信任,因此客户端首先就要了解一下,你这个证书可否用来进行验证。若是不行的话,那么你此次链接就是不被信任的,就没有绿色的小锁。这就须要了解一下,客户端的验证过程。

CA 链式验证

首先,什么叫作可信的证书呢? 咱们先要明白一个道理,HTTPS 是先创建在人与人之间的相互信任上,而后才创建在机器与机器的相互信任上。假如,根证书 A 机构,恶意的将一个之前颁发过的证书,又给了另一个不要脸拦截站点(好比,用来插广告的)。这样,我拿到了这个证书后,就能够本身搭一个服务器,用来进行拦截浏览,监管里你网站,并强行插广告。这就被称为不可信的机构/证书。 而验证的可行性,一般又跟机构的权威性有着极大的关系。它基本的验证过程简述就是(按照上面的层级):

  • www.villainhr.com 问 TrustAsia DV SSL,个人证书可不可信?
  • 可信!ok,继续。TrustAsia DV SSL 问 VeriSign Class 3,个人证书可不可信
  • 可信!ok,而后便开始 TLS/SSL 链接。

若是上述任一步骤出现问题,那么该次 TLS/SSL 就不会进行,会回退。那么它们在询问的时候,会不会发送网络请求呢? 不会~ 由于,电脑在初始化时,会自带不少可信任的证书机构(即,Root CA),也就是咱们刚刚提到的 VeriSign Class 3 的证书机构。以及,可以签发证书的二级机构(比较少)。到时候,浏览器会自动的根据数字签名来进行证书的验证。

CA 合法验证

上面已经阐述了,CA 证书的合法性是自下而上的验证方式。那么它们具体验证协议是怎样的呢? 在说以前,咱们先说几个概念:

  • 数字签名:它是用颁发机构的私钥,对下级证书的公钥进行加密生成的值。digital_sign = CA_pr_key + sub_Cer_ppu_key。
  • 解密:用颁发机构的公钥对数字签名进行解密,对比下级证书的公钥和解密后的值是否一致。

CA 验证首先须要说一下它的颁发过程:

  • 颁发机构 A,用本身的私钥将须要生成的下级证书 B 的公钥进行加密,生成数字签名,而后再带上相关信息:公钥,公钥的指纹,数字签名,证书名,签发机构等。

而后,验证过程就是根据这个来的:

  • 浏览器解析下级证书 B 的相关信息,找到签发机构和数字签名。
  • 而后,找到签发机构 A,使用 A 的公钥去解密数字签名,而后对比下级证书 B 的公钥。若是成功则合法,反之,不合法。

而上面的三级证书层级,也是一样的道理,自上而下的找就 ok。固然,有时候为了验证的速度,会作一些缓存,这样就没必要再进行验证了。因此,根据上面的描述,有童鞋可能会想到,能不能自签证书呢?反正,浏览器也是从本地找的。 固然能够,openssl 就能够生成你本身的 CA。不过须要注意的是,你生成的 CA 只是在你本身的电脑上使用,若是你想保证你的 CA 在其余电脑上也能使用的话(这是不可能的),那就用钱砸就 ok。 具体的过程能够参考:生成本身的 CA 证书。 之前,在使用 Charles 和 Fiddler 的时候,一直在想,它们是怎么作到,将本身的证书,变成签发机构证书。

Charles 签发证书

后来发现,它是把证书中的相关字段该成它的证书内容。不过,对于某些高级证书,仍是会有一些问题,好比,wx.qq.com(微信的)

另外,为了证书的可靠性,提出了 Certificate Transparency 项目,实际上,就是让证书机构公开它的签发流水。防止出现重复签发。

证书的吊销

如今有个问题,为何证书有过时时间呢? 这一样是为了安全性,前面说过,若是你的证书发生了泄漏(实际上就是私钥)。那么,其余服务器就能够做为一个代理去拦截你的流量。这时候,因为过时的缘由,可能一段时间后,中间恶意的服务器就没用了,另外,若是你发现了你遗失了证书,能够向颁发机构去挂失。 另外,还有一个缘由是证书吊销的 CRL 机制。简单来讲,就是有一个列表来记录当前时间,该颁发机构被吊销的证书 list。若是,没有过时时间的话,那么这个 list,会随时间程指数增加,引入过时机制的话,该 list 只要记录当前没过时但吊销的证书信息便可。 证书的吊销有两种机制:CRL,OCSP

CRL

CRL(Certificate Revocation List),即,证书吊销列表。CA 机构会生成一个列表,列表里面是当前周期被吊销证书的序列号,当进行证书验证时,一样也会进行验证该项。若是,已是吊销证书的话,那么该次 TLS/SSL 链接也会失败。 咱们能够从证书信息中找到 CRL URI:

CRL证书信息

该协议虽然简单,但,缺陷仍是比较多的。

  • 下载时间。由于该 list 不是自带的,须要从颁发机构下载,这就形成了网络时延。
  • 缓存时间。若是存在缓存,就存在了信息不一样步的问题,若是一个证书已通过期,但缓存中显示的是未过时,那么也是一个安全问题。

OCSP

OCSP(Online Certificate Status Protocol),即,在线证书状态协议。它经过在线请求的方式来进行验证,不须要下载整个 list,只须要将该证书的序列号发送给 CA 进行验证。固然,验证经过也会有必定的缓存期。不过,因为验证也会存在时延。另外,部署 OCSP 对 CA 也有必定的要求,CA 要搭建的一个服务器来接受验证,而且,该服务器的性能要好(负载很大)。

OCSP stapling

OCSP stapling 常称为: TLS Certificate Status Request extension。是 OCSP 的另一种实现方式,由于前两个(OCSP,CRL)都是由客户端去验证证书是否吊销,而且都会发送请求。而 OCSPs(OCSP stapling)则是直接在 server 端,进行证书的有效性验证。server 会周期性的向 CA 机构发送请求,验证有效性,并在 certificate 阶段,发送相应的签名信息。不过,该协议是创建在,咱们彻底信任 serve 的状况下,这里就排除了一些恶意的中间服务器。详情能够参考:OCSP stapling

TLS/SSL 优化

TLS/SSL 主要的性能调优简单包括:启用 False Start, OSCP Stapling, 选择合适 cipher suite, resumption 等。另外,若是你追求 fashion, 那么 HTTP/2 应该是个不错的选择。 想要作 TLS/SSL 优化,那么你必须了解,TLS/SSL 握手的整个过程是什么。固然,你能够买个证书,从头本身搭建一个服务器,可是,这样只能证实 你颇有钱 外,其它也证实不了什么。由于,这彻底能够本身内网搭一个呀~ 能够参考:10s 自建证书. 这里,咱们结合 nginx 来具体对 TLS/SSL handshake 优化,作个总体的阐述。

设置 session 缓存

session 缓存设置可让两次的 RTT,变为一次,这至关于快了一倍(不包括,密钥计算等)。不一样的 server 设置 session 的办法有不少,这里以 nginx 为例。在 nginx 中,支持的是 Session ID 的形式,即在 server 中缓存之前 session 的加密内容。涉及的字段有两个,ssl_session_cachessl_session_timeout

  • ssl_session_cache:用来设置 session cache 上限值,以及是否在多个 worker 之间共享
  • ssl_session_timeout:用来设置 session cache 存储的时间

看个 demo 吧:

ssl_session_cache shared:SSL:10m;
ssl_session_timeout 20m;
复制代码

表示的意思是:session cahce 会在不一样的 worker 之间分享,假设 1MB 只能存储 8000 次握手的信息。那么, 10 MB 一共能够存储 80000 次握手信息。若是超出,则不会存储。缓存信息存在时长为 20分钟。 另外,你也能够开启 session ticket。ST(session ticket) 须要一个sign 参数,使用 openssl 建立便可。

$ openssl rand 48 > ticket.key
# 在 nginx 中开启
ssl_session_tickets on; 
ssl_session_ticket_key ticket.key;
复制代码

选择合适的 cipher suite

这里先声明一下,你的证书的内容和你的加密套件实际没有半毛钱关系,这主要仍是取决于你的服务器的支持程度以及客户端的支持度。另外,若是你想启用 False Start,这也可套件的选择有很大的关系。咱们来看一下若是设置吧。在 nginx 中,主要用到两个指令:

ssl_prefer_server_ciphers on;
ssl_ciphers xxx;
复制代码
  • ssl_prefer_server_ciphers: 用来告诉客户端,要按照我提供的加密套件选择。
  • ssl_ciphers: 具体设置的加密套件内容,使用 : 分隔。

支持性最高的就是使用:

// 让浏览器来决定使用哪个套件(额。。。最后的手段)
ssl_ciphers  HIGH:!aNULL:!MD5;
复制代码

通常状况,仍是应该本身来决定使用哪个套件,这样安不安全由本身说了算。具体能够参考 mozilla 的套件配置。这里简单放一个,比较安全的,下面全部的套件都必须支持 Forwar Secrecy

ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5
复制代码

不过,如下的加密套件,最好不要使用,由于基本上都不安全:

  • aNULL: 是一种非标准的 DH 密钥交换套件。容易被中间人攻击。
  • eNULL: 没有加密方式,明文交换
  • EXPORT: 一种弱加密方式,老美那边早期使用的
  • RC4: 使用已经废弃的 ARCFOUR 算法
  • DES: 使用已经废弃的 Data Encryption 标准
  • SSLv2: 老版本 SSL2.0 的加密套件(最少,你也写 SSLv3 嘛)
  • MD5: 直接使用 MD5 加密方式

上面那些只能给一些远古浏览器使用,基本上在选择中是做为垫底的选择。

False Start

另外,怎么在 nginx 中开启 False Start 呢? 这其实和服务器并无多大的关系,关键仍是你选择的套件和 NPN/ALPN 协议的做用。

  • 首先,你的加密套件必须具备 Forward Secrecy,不然开不了。
  • 浏览器须要使用 NPN 或者 ALPN 告诉服务器,该所需的协议版本,而后再决定开不开启。

那么,在 nginx 中,咱们只要选择好合适的加密套件便可。这里就放一份现成的吧

ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256::DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5';
复制代码

使用 DH 密钥交换

DH 的加密过程,上面已经说过了。DH 自带两个公共的参数,因此,这必须手动进行建立(实际上就是将参数 sign 一遍)。

// 建立一个 DH param
openssl dhparam 2048 -out dhparam.pem
复制代码

而后,调用该文件

ssl_dhparam dhparam.pem;
复制代码

这样,你就正式的开启的 DH 加密模式。若是你使用抓包工具观察一下,此时 DH 应该会在 Server Hello 里:

server Hello 信息

不过,因为历史缘由,DH param 已经使用的长度是 1024,好比: 采用 Oakley group 2 版本。如今,比较流行的 DH 加密方式是 ECDHE,它和之前的加密方式(DHE)比起来,在密钥生成这块会快不少。一样,因为历史缘由,它的基本条件比较高:(其实也还好)

  • Android > 3.0.0
  • Java > 7
  • OpenSSL > 1.0.0

开启 OCSP Stapling

OCSP Stapling 是验证证书权威性的一种手段,前面还有两种 CRL 和 OCSP。不过,它们都是让 client 本身去验证。而 OCSP Stapling 则把验证这块放到了 server 里,经过按期检查,来减小网络时间中的消耗。要开启 OCSP Stapling 首先是须要你证书的 chain 文件,该是用来详细说明,从根证书到你的证书中间所要经历的全部验证(和其余两种验证手段同样)。那如何获得 chain 文件呢?直接去问你的证书颁发机构,这个又不是啥秘密文件。若是是自发证书(本身测试用的),那就本身生成。将全部的中间证书按照 bottom to up 放到一个文件里:

cat intermediate/certs/intermediate.cert.pem \
      certs/ca.cert.pem > intermediate/certs/ca-chain.cert.pem;
复制代码

那么 ca-chain.cert.pem 就是 OSCP stapling 验证文件。而后在 nginx 开启便可。

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate ca-chain.cert.pem;
resolver 8.8.8.8 8.8.4.4; // 默认使用 Google 的
复制代码

关于 DNS 解析,一样你也须要问一下证书提供商,固然,该值能够不用管。下面也一样适用

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate ca-chain.cert.pem;
复制代码

开启事后,你可使用 openssl s_client -connect www.yourDomainName.com:443 来测试一下,检测是否开启成功。

开启 HSTS

HSTS(HTTP Strict Transport Security) 实际上就是一个响应头,没啥很特别的,具体内容就是,你全部对外部的请求都是 https,因此这有一个问题,若是你的图片地址是 http 的,那么最终的结果,会变为 https://xxx,有可能会形成资源丢失的状况,因此,开不开启还须要慎用。

Strict-Transport-Security: max-age=15768000 # 设定 6 个月的强制期
复制代码

在有效时间内,客户端都会尝试使用 https 访问你的站点,若是在这期限里你的证书过时了,开不了 https。那么,呵呵。

使用 SNI

SNI 就是针对一个 IP 手握不少张证书时,用到的协议机制,这主要是用来区分,不一样的 host,使用不一样的证书。SNI 详情上面已经说过了,这里就不赘述了。主要使用格式就是不一样的 server_name 搭配不一样的 certificate

server{
    server_name www.abc.com;
    ssl_certificate abc.crt;
    ssl_certificate_key abc.crt.key;
}
server{
    server_name www.def.com;
    ssl_certificate def.crt;
    ssl_certificate_key def.crt.key;
}
复制代码

如何开启呢?换个高版本的 nginx 就好了。你可使用 nginx -V 检查你的 nginx 是否带有

TLS SNI support enabled
复制代码

完整示例

最后,放一份完整的吧:

server {
        listen 443 ssl http2; # 默认打开 http2
        listen [::]:443 ssl http2;

        ssl_certificate /etc/nginx/cert/bjornjohansen.no.certchain.crt;
        ssl_certificate_key /etc/nginx/cert/bjornjohansen.no.key;

        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 20m;

        ssl_prefer_server_ciphers on;

        ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;

        ssl_dhparam /etc/nginx/cert/dhparam.pem;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_trusted_certificate /etc/nginx/cert/trustchain.crt;
        resolver 8.8.8.8 8.8.4.4; # 看状况选择 DNS IP

        #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        # 我通常不开 HSTS
        # add_header Strict-Transport-Security "max-age=31536000" always;
}
复制代码

参考列表

这个,配置也很简单,你能够从 Mozilla 里得到更丰富的内容。详情能够参考:

另外,还有一些测试工具和生成工具,这里也提供一份 list: