本文只是对上面地址做的一个笔记。用于涉及HTTPS性能测试时分析问题、提出建议。 

 

完全握手的HTTPS性能不及HTTP的10%,主要是RSA算法,对性能的影响占75%左右。

优化步骤:

1.减少完全握手的发生;

2.不能减少的完全握手,使用代理计算;

3.对称加密的优化。

 

TLS层

1.简化握手比完全握手少一个RTT(网络交互),完全握手需要两个握手交互才能进行第三部应用层的传输,而简化握手只需要一个RTT就能进行应用层的数据传输。

2.完全握手有SeraverKeyExchange的消息,另外还有Certificate的消息,而简化握手并不需要。

 

实现

TLS协议层有两个策略可以实现:

1.Session ID

  Session ID由服务器生成并返回给客户端,客户端再次发起SSL握手时会携带Session ID,服务端拿到后会从自己的内存查找,如果找到便说明之前已经发生过完全握手,是可以信任的。

2.Session Ticket

  也是客户端发起握手时会带上的扩展,服务器拿到Session Ticket后对它进行解密,如果解密成功了就说明是可信任的。

 

实现的局限

1.Nginx只支持单机多进程共享Session Cache。但大部分环境都是多台Nginx机器,因此如果有多台机器接入就容易出现下面问题:1号Nginx产生ID并返回给用户,用户隔一段时间再次访问的时候,其携带的ID会随机落到某一台(包括1号)Nginx上面,这样就无法查找之前的ID,不能进行简化握手。

2.openssl提供了Session Cache的callback可以回调,但这个回调函数是同步的,而Nginx是完全异步事件驱动的框架,如果Nginx调用这个callback进行网络查找,加入这个网络查找需要1毫秒,这意味着整体性能不会超过1k次。

 

Session Cache的两个改进方案

1.IP Hash

  根据IP做Hash的负载均衡策略,可以保证相同的IP用户永远在一台Nginx上面。

  缺点:

  1)容易导致热点,很多Net网关出口IP用户的访问量非常大,也就是说有一些IP请求非常大导致某一台机器负载不均衡;

  2)用户IP可能会经常变化,特别在移动端上,在Wi-Fi和移动网络(2G,3G,4G)环境下切换导致IP变化。

2.分布式缓存(部分是Session Cache)

  假如用户开始发起握手,1号Nginx生成ID会写入到一个全局的,比如redis cache里,然后返回给用户。用户下一次发起握手的时候,直接在全局的Session Cache查找。

  下面是两个开源方案:

  a)OpenResty,它提供了SSL Cache全局查找的指令;

  b)BoringSSL,这是Google fork OpenSSL的版本,也是SSL层面上实现异步的Session Cache查找。

 

Session Ticket

  Session Cache必须在服务端做缓存,会浪费很大内存。而Session Ticket不需要,但也有个缺点:默认情况下,Nginx各自的Session Ticket加解密密钥是不同的(这里的密钥指的是Session Ticket的对称加解密密钥而不是Certificate对应的私钥)。

  解决方法:将所有Nginx机器配置成同一个加解密密钥。

 

Self Session Ticket

  页面的关闭or重启,都可能导致Session ID和Session Ticket丢失。

  实现Self Session Ticket,将Ticket存储在硬盘里面,而不是内存。

  会带来一定风险,但可以做一些限制:
  1.Ticket存储在App的私有路径(没有root的手机一般不能读取到私有路径的数据);

  2.对安全系数要求不高的业务开启这个功能;

  3.这个密钥开关做到随时控制。

 

异步代理计算的原理和实现

  异步代理计算主要分为3个步骤:
  1.算法分离,把最消耗CPU资源的算法剥离出来,不让它消耗本机的CPU资源;

  2.代理计算,既不消耗本机的CPU资源,可以使用要硬件加速卡或者空闲的CPU资源来完成计算;

  3.异步执行,把算法分离出来交给计算集群去计算的时候,这个过程是一步的,我不需要同步等待计算结果返回。

 

算法分离

  要分离的主要是密钥交换算法(非对称密钥交换算法),密钥交换算法最常用的是三类:

  考虑兼容性  ----RSA

  目前使用最多 ----ECDHE_RSA

  非常消耗性能 ----DHE_RSA

  RSA和ECDHE_RSA消耗CPU资源的原因

  RSA主要是对客户端发回来的pre_master_secret进行解密,消耗CPU资源的过程是私钥解密的计算;

  ECDHE_RSA则有两个步骤:

  1.生成ECC椭圆曲线的公钥和几个重要的参数;

  2.对这几个参数进行签名,客户端要确保参数是服务端发送过来的,就是通过RSA签名来保证。

  RSA签名同样有两个步骤:

  1.通过SHA1进行Hash计算;

  2.对Hash结果进行私钥加密。

  如果e或者d这个指数是一个接近2^2048的数字,那就非常消耗CPU,此为RSA为什么消耗CPU的最直接的数学解释。

c=m^e*mod(n)

m=c^d*mod(n)

  协议层分离

  以ECDHE_RSA为例,由于使用了ECC参数和RSA签名,ServerKeyExchange需要进行分离。

  RSA密钥交换的分离,RSA非对称密钥交换算法不需要ServerKeyExchange的消息,单需要对Client发过来的ClientKeyExchange进行解密操作。

 

异步代理计算——架构

  最简单的配置,Nginx+OpenSSL,然后把证书和私钥放上去,打开443端口,但这消耗的都是本机的CPU资源,性能会很差。

  异步硬件极速卡代理:

  用户发起HTTPS握手,涉及到私钥计算(比如ServerKeyExchange和对ClientKeyExchange解密)的时候会把ECC的参数剥离出来发送到计算集群,发送出去同事立马异步返回,又可以接收其他用户的请求。

  计算集群把结算结果返回给Nginx,Nginx又触发最初的用户场景,从而完成HTTPS握手。

  还可以使用线上的空闲CPU资源。

  这种方案与协议、证书没有关系。只要算法安全,过程就能保持稳定,维护成本也低。

 

异步代理计算——工程实现

  Nginx尽管模块机制丰富,但须要在HTTP头部数据解析完成之后才能介入的处理,即在SSL握手完成前无法介入处理,必须对事件框架进行修改。

  关于OpenSSL,须要对OpenSSL的协议栈进行修改,主要涉及到s3_srvr.c这个文件,这个文件主要是实现OpenSSL握手的协议栈。

  开源方案:OpenSSL1.1.0

  该方案已经支持异步事件,同样还是需要修改Nginx才能实现异步。性能强大,纯ECDHE_RSA性能比本机能提升3.5倍。且解耦做得很好。

 

ECC椭圆曲线的优化

  不是针对算法本身进行的优化,而是使用OpenSSL的官方版本过程中需要注意的地方。

  一般来说密钥越大,性能越差。P-256看上去应该比P-224要慢,但实际上P-256比P-224性能高了4倍,正是因为Intel进行过优化,这个优化是在1.0.1L之后才加入的。

  尽量使用NIST P-256这条曲线。

对称加密算法的优化

  1.块式对称加密算法

  AES-GCM性能最高。AES-NI同样是Intel CPU提供的硬件加速指令,比不开启的CPU性能要提升5倍左右,2010年之后的Intel CPU都是支持的,但需要注意如要要直接使用AES对称加解密,一定要使用OpenSSL封装的EVP_EncryptInit_ex函数,默认的AES_encrypt函数是不会用硬件加速指令的,因此性能会更差;

  2.流式对称加密算法

  Chacha20-Poly1305专门针对移动端CPU优化的流式对称密码算法,性能比普通算法提高3倍。但只适用于稍低端,且不支持AES-NI指令的手机才能提高3倍。如iPhone支持AES-NI,但它的性能还是会比AES-GCM要差。

  RC4、SSL3.0已经不安全了。

  SSL3.0为什么不安全?

  a)SSL3.0存在AES-CBC的缓存Poodle漏洞;

  b)RC4存在Bios偏移的漏洞。

  如果开启SSL3.0的话,出于安全的考虑,支持RC4。并且RC4的算法性能比AES-CBC高。