TLS算法组合

在TLS中,5类算法组合在一起,称为一个CipherSuite:

  • 认证算法

  • 加密算法

  • 消息认证码算法 简称MAC

  • 密钥交换算法

  • 密钥衍生算法

比较常见的算法组合是 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 和  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 都是ECDHE 做密钥交换,使用RSA做认证,SHA256做PRF算法。

一个使用AES128-CBC做加密算法,用HMAC做MAC。

一个使用AES128-GCM做加密算法,MAC由于GCM作为一种AEAD模式并不需要。

SSL协议的握手过程

第一步,爱丽丝给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法。

第二步,鲍勃确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。

第三步,爱丽丝确认数字证书(对证书信息进行md5或者hash后的编号==用证书机构的公钥对加密的证书编号解密后的证书编号)有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥(鲍勃的公钥),加密这个随机数,发给鲍勃。

第四步,鲍勃使用自己的私钥,获取爱丽丝发来的随机数(即Premaster secret)。

第五步,爱丽丝和鲍勃根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session key),用来加密接下来的整个对话过程。

https要使客户端与服务器端的通信过程得到安全保证,必须使用对称加密算法并且每个客户端的算法都不一样,需要一个协商过程,但是协商对称加密算法的过程,需要使用非对称加密算法来保证安全,直接使用非对称加密的过程本身也不安全,会有中间人篡改公钥的可能性,所以客户端与服务器不直接使用公钥,而是使用数字证书签发机构颁发的证书来保证非对称加密过程本身的安全。这样通过这些机制协商出一个对称加密算法,就此双方使用该算法进行加密解密。从而解决了客户端与服务器端之间的通信安全问题。

Java 对SSL的支持

JDK7的client端只支持TLS1.0,服务端则支持TLS1.2。

JDK8完全支持TLS1.2。

JDK7不支持GCM算法。

JDK8支持GCM算法,但性能极差极差极差,按Netty的说法:

  • Java 8u60以前多版本,只能处理1 MB/s。

  • Java 8u60 开始,10倍的性能提升,10-20 MB/s。

  • 但比起 OpenSSL的 ~200 MB/s,还差着一个量级。

Netty 对SSL的支持

Netty既支持JDK SSL,也支持Google的boringssl, 这是OpenSSL 的一个fork,更少的代码,更多的功能。

依赖netty-tcnative-boringssl-static-linux-x86_64.jar即可,它里面已包含了相关的so文件,再也不用管Linux里装没装OpenSSL,OpenSSL啥版本了。

性能问题的出现

JDK7的JMeter HTTPS客户端,连接JDK8的Netty服务端时,速度还可以。

JDK8的JMeter HTTPS客户端,则非常慢,非常慢,非常吃客户端的CPU。

按套路,在JMeter端增加启动参数 -Djavax.net.debug=ssl,handshake  debug 握手过程。

(OpenSSL那边这个参数加了没用)

*** ClientHello, TLSv1.2,可以看到,Client端先发起协商,带了一堆可选协议

Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256…]

*** ServerHello, TLSv1.2 然后服务端回选定一个

Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

还可以看到,传输同样的数据,不同客户端/服务端组合下有不同的纪录:

Client: JDK7 JDK SSL + Server: JDK7/8 JDK SSL

**TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

WRITE: TLSv1 Application Data, length = 32

WRITE: TLSv1 Application Data, length = 304

READ:  TLSv1 Application Data, length = 32

READ:  TLSv1 Application Data, length = 96

READ:  TLSv1 Application Data, length = 32

READ:  TLSv1 Application Data, length = 10336

Client: JDK8 JDK SSL + Server: JDK8 Open SSL

** TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

Thread Group 1-1, WRITE: TLSv1.2 Application Data, length = 300

Thread Group 1-1, READ: TLSv1.2 Application Data, length = 92

Thread Group 1-1, READ: TLSv1.2 Application Data, length = 10337

原因分析

JMeter Https 用的是JDK8 SSL,很不幸的和服务端的OpenSSL协商出一个JDK8实现超慢的TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256。

对于服务端/客户端都是基于Netty + boringssl的RPC框架,使用TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 仍然是好的,毕竟更安全。

但Https接口,如果不确定对端的是什么,JDK7 SSL or JDK8 SSL or OpenSSL,为免协商出一个超慢的GCM算法,Server端需要通过配置,才决定要不要把GCM放进可选列表里。

解决方法

平时是这样写的:

SslContext sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())  .sslProvider( SslProvider. OPENSSL).build();

如果不要开GCM,那把ReferenceCountedOpenSslContext里面的DEFAULT_CIPHERS抄出来,删掉两个GCM的。

List<String> ciphers = Lists.newArrayList(“ECDHE-RSA-AES128-SHA”, “ECDHE-RSA-AES256-SHA”, “AES128-SHA”, “AES256-SHA”, “DES-CBC3-SHA”);

SslContext sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).sslProvider( SslProvider.OPENSSL).ciphers(ciphers).build();

总结

  • OpenSSL(boringssl)比JDK SSL 快10倍,10倍!!! 所以Netty下尽量都要使用OpenSSL。

  • 在确定两端都使用OpenSSL时,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 仍然是好的,毕竟更安全,也是主流。

  • 对端如果是JDK8 SSL时,Server端要把GCM算法从可选列表里拿掉。

Netty SSL性能调优的更多相关文章

  1. Netty实战之性能调优与设计模式

    设计模式在Netty 中的应用(回顾): 单例模式要点回顾: 一个类在任何情况下只有一个对象,并提供一个全局访问点. 可延迟创建. 避免线程安全问题. 在我们利用netty自带的容器来管理客户端链接的 ...

  2. 记一次Web服务的性能调优

    前言 一个项目在经历开发.测试.上线后,当时的用户规模还比较小,所以刚刚上线的项目一般会表现稳定.但是随着时间的推移,用户数量的增加,qps的增加等因素会造成项目慢慢表现出网页半天无响应的状况.在之前 ...

  3. Advacned Puppet: Puppet Master性能调优

    本文是Advanced Puppet系列的第一篇:Puppet master性能调优,谈一谈如何优化和提高C/S架构下master端的性能. 故事情节往往惊人地类似:你是一名使用Puppet管理线上业 ...

  4. Spark性能调优之Shuffle调优

    Spark性能调优之Shuffle调优    • Spark底层shuffle的传输方式是使用netty传输,netty在进行网络传输的过程会申请堆外内存(netty是零拷贝),所以使用了堆外内存. ...

  5. HTTPS 之 TLS 性能调优

    HTTPS(HTTP over SSL)是以安全为目标的 HTTP 通道,可以理解为 HTTP + SSL/TLS,即在 HTTP 下加入 SSL/TLS 层作为安全基础.其中 TLS 的前身是 SS ...

  6. Redis基础、高级特性与性能调优

    本文将从Redis的基本特性入手,通过讲述Redis的数据结构和主要命令对Redis的基本能力进行直观介绍.之后概览Redis提供的高级能力,并在部署.维护.性能调优等多个方面进行更深入的介绍和指导. ...

  7. Tomcat性能调优后, 启动出现警告问题 [did not find a matching property.]

    http://blog.csdn.net/dracotianlong/article/details/8963594 Tomcat性能调优后, 启动出现警告问题 [did not find a mat ...

  8. Redis 基础、高级特性与性能调优

    本文将从Redis的基本特性入手,通过讲述Redis的数据结构和主要命令对Redis的基本能力进行直观介绍.之后概览Redis提供的高级能力,并在部署.维护.性能调优等多个方面进行更深入的介绍和指导. ...

  9. Java性能调优:利用JMC分析性能

    Java性能调优作为大型分布式系统提供高性能服务的必修课,其重要性不言而喻. 好的分析工具能起到事半功倍的效果,利用分析利器JMC.JFR,可以实现性能问题的准确定位. 本文主要阐述如何利用JMC分析 ...

随机推荐

  1. redis----内部数据结构学习

    整数集合 1.应用 用于有序.无重复的保存多个整数值 自动选择该用什么长度的整数类型保存数据

  2. 7个常见Javascript框架介绍

    设计开发中的“框架”指一套包含工具.函数库.约定,以及尝试从常用任务中抽象出可以复用的通用模块,目标是使设计师和开发人员把重点放在任务项目所特有的方面,避免重复开发.通俗的讲,框架就是最常用的java ...

  3. 查看SSD寿命

    查看SSD寿命 起初买mac book pro的时候挺担心SSD使用寿命的,过保了后,还搞了个移动硬盘,尽可能的把编译什么的都移动到移动硬盘上进行,实际上这样做都是没有必要的. 安装软件smartct ...

  4. C# 连接 IBM MQ

    安装 IBM WebSphere MQ:http://www-01.ibm.com/software/integration/wmq/explorer/downloads/ 正确安装要注意几个地方,集 ...

  5. C# Pinvoke判断是UEFI模式还是BIOS模式

    [DllImport("kernel32.dll", SetLastError = true)] public static extern UInt32 GetFirmwareEn ...

  6. 腾讯云/阿里云/微软云安装ISO镜像系统方法

    如今云服务的盛行,我们的开发和应用中场景应用也层出不穷,有时我们需要安装自由的镜像却越来越难,甚至有些云出于安全原因自己用户安装自由镜像,那么今天将带给大家安装自有镜像的方法. 前提条件:你的现有服务 ...

  7. iOS开发应用结构化资源储备

    1.常用跳转 class 1.1 工程配置及项目初始化 1.2 超常用代码规范 1.3 一种传统的程序模块化马甲包开发架构 2.UI显示部分 UIButton UILabel UIImageView ...

  8. python之爬虫(二)爬虫的原理

    在上文中我们说了:爬虫就是请求网站并提取数据的自动化程序.其中请求,提取,自动化是爬虫的关键!下面我们分析爬虫的基本流程 爬虫的基本流程 发起请求通过HTTP库向目标站点发起请求,也就是发送一个Req ...

  9. Servlet实现Cookie读写

    前言 程序员老婆让程序员去外面买东西,说,老公,你出去买一笼包子吧,遇到卖西瓜的就买一个.老公高兴的出去了,一会儿带着一个包子回来了,老婆很是郁闷问,怎么只买了一个包子,程序员说:因为我看到卖西瓜的了 ...

  10. WPF中的DataGridTemplateColumn实现点击列标题排序

    在DataGrid中使用模板列时,默认功能中对点击列标题是不对列值进行排序的,要排序就需要添加以下两个属性: 1.CanUserSort="True" 2.SortMemberPa ...