百度已经于近日上线了全站HTTPS的安全搜索,默认会将HTTP请求跳转成HTTPS。本文重点介绍HTTPS协议,并简单介绍部署全站HTTPS的意义。 本文最早发表于百度运维部官方博客
HTTPS可以认为是HTTP + TLS。HTTP协议大家耳熟能详了,目前大部分WEB应用和网站都是使用HTTP协议传输的。 TLS是传输层加密协议,它的前身是SSL协议,最早由netscape公司于1995年发布,1999年经过IETF讨论和规范后,改名为TLS。如果没有特别说明,SSL和TLS说的都是同一个协议。 HTTP和TLS在协议层的位置以及TLS协议的组成如下图:
TLS协议主要有五部分:应用数据层协议,握手协议,报警协议,加密消息确认协议,心跳协议。 TLS协议本身又是由record协议传输的,record协议的格式如上图最右所示。
目前常用的HTTP协议是HTTP1.1,常用的TLS协议版本有如下几个:TLS1.2, TLS1.1, TLS1.0和SSL3.0。其中SSL3.0由于POODLE攻击已经被证明不安全,但统计发现依然有不到1%的浏览器使用SSL3.0。TLS1.0 也存在部分安全漏洞,比如RC4和BEAST攻击。 TLS1.2和TLS1.1暂时没有已知的安全漏洞,比较安全,同时有大量扩展提升速度和性能,推荐大家使用。 需要关注一点的就是TLS1.3将会是TLS协议一个非常重大的改革。不管是安全性还是用户访问速度都会有质的提升。不过目前没有明确的发布时间。 同时HTTP2也已经正式定稿,这个由SPDY协议演化而来的协议相比HTTP1.1又是一个非常重大的变动,能够明显提升应用层数据的传输效率。
百度使用HTTPS协议主要是为了保护用户隐私,防止流量劫持。 HTTP本身是明文传输的,没有经过任何安全处理。例如用户在百度搜索了一个关键字,比如“苹果手机”,中间者完全能够查看到这个信息,并且有可能打电话 过来骚扰用户。也有一些用户投诉使用百度时,发现首页或者结果页面浮了一个很长很大的广告,这也肯定是中间者往页面插的广告内容。如果劫持技术比较低劣的 话,用户甚至无法访问百度。 这里提到的中间者主要指一些网络节点,是用户数据在浏览器和百度服务器中间传输必须要经过的节点。比如WIFI热点,路由器,防火墙,反向代理,缓存服务器等。 在HTTP协议下,中间者可以随意嗅探用户搜索内容,窃取隐私甚至篡改网页。不过HTTPS是这些劫持行为的克星,能够完全有效地防御。 总体来说,HTTPS协议提供了三个强大的功能来对抗上述的劫持行为: 1. 内容加密。浏览器到百度服务器的内容都是以加密形式传输,中间者无法直接查看原始内容。 2. 身份认证。保证用户访问的是百度服务,即使被DNS劫持到了第三方站点,也会提醒用户没有访问百度服务,有可能被劫持 3. 数据完整性。防止内容被第三方冒充或者篡改。
那HTTPS是如何做到上述三点的呢?下面从原理角度介绍一下。
加密算法一般分为两种,对称加密和非对称加密。所谓对称加密(也叫密钥加密)就是指加密和解密使用的是相同的密钥。而非对称加密(也叫公钥加密)就是指加密和解密使用了不同的密钥。
对称内容加密强度非常高,一般破解不了。但存在一个很大的问题就是无法安全地生成和保管密钥。假如客户端软件和服务器之间每次会话都使用固定的,相 同的密钥加密和解密,肯定存在很大的安全隐患。如果有人从客户端端获取到了对称密钥,整个内容就不存在安全性了,而且管理海量的客户端密钥也是一件很复杂 的事情。 非对称加密主要用于密钥交换(也叫密钥协商),能够很好地解决这个问题。浏览器和服务器每次新建会话时都使用非对称密钥交换算法协商出对称密钥,使用这些 对称密钥完成应用数据的加解密和验证,整个会话过程中的密钥只在内存中生成和保存,而且每个会话的对称密钥都不相同(除非会话复用),中间者无法窃取。 非对称密钥交换很安全,但同时也是HTTPS性能和速度严重降低的“罪魁祸首”。想要知道HTTPS为什么影响速度,为什么消耗资源,就一定要理解非对称密钥交换的整个过程。 下面重点介绍一下非对称密钥交换的数学原理及在TLS握手过程中的应用。
在非对称密钥交换算法出现以前,对称加密一个很大的问题就是不知道如何安全生成和保管密钥。非对称密钥交换过程主要就是为了解决这个问题,使得对称密钥的生成和使用更加安全。 密钥交换算法本身非常复杂,密钥交换过程涉及到随机数生成,模指数运算,空白补齐,加密,签名等操作。 常见的密钥交换算法有RSA,ECDHE,DH,DHE等算法。它们的特性如下:
建议优先支持RSA和ECDH_RSA密钥交换算法。原因是: 1. ECDHE支持ECC加速,计算速度更快。支持PFS,更加安全。支持false start,用户访问速度更快。 2. 目前还有至少20%以上的客户端不支持ECDHE,我们推荐使用RSA而不是DH或者DHE,因为DH系列算法非常消耗CPU(相当于要做两次RSA计算)。
需要注意通常所说的ECDHE密钥交换默认都是指ECDHE_RSA,使用ECDHE生成DH算法所需的公私钥,然后使用RSA算法进行签名最后再计算得出对称密钥。 非对称加密相比对称加密更加安全,但也存在两个明显缺点: 1. CPU计算资源消耗非常大。一次完全TLS握手,密钥交换时的非对称解密计算量占整个握手过程的90%以上。而对称加密的计算量只相当于非对称加密的0.1%,如果应用层数据也使用非对称加解密,性能开销太大,无法承受。 2. 非对称加密算法对加密内容的长度有限制,不能超过公钥长度。比如现在常用的公钥长度是2048位,意味着待加密内容不能超过256个字节。 所以公钥加密目前只能用来作密钥交换或者内容签名,不适合用来做应用层传输内容的加解密。
非对称密钥交换算法是整个HTTPS得以安全的基石,充分理解非对称密钥交换算法是理解HTTPS协议和功能的关键。 下面分别通俗地介绍一下RSA和ECDHE在密钥交换过程中的应用。
RSA算法的安全性是建立在乘法不可逆或者大数因子很难分解的基础上。RSA的推导和实现涉及到了欧拉函数和费马定理及模反元素的概念,有兴趣的读者可以自行百度。 RSA算法是统治世界的最重要算法之一,而且从目前来看,RSA也是HTTPS体系中最重要的算法,没有之一。 RSA的计算步骤如下:
实际应用中,(n,e)组成了公钥对,(n,d)组成了私钥对,其中n和d都是一个接近2^2048的大数。即使现在性能很强的CPU,想要计算〖m ≡ c〗^d mod (n),也需要消耗比较大的计算资源和时间。 公钥对(n, e)一般都注册到了证书里,任何人都能直接查看,比如百度证书的公钥对如下图,其中最末6个数字(010001)换算成10进制就是65537,也就是公钥对中的e。e取值比较小的好处有两个:
介绍完了RSA的原理,那最终会话所需要的对称密钥是如何生成的呢?跟RSA有什么关系? 以TLS1.2为例简单描述一下,省略跟密钥交换无关的握手消息。过程如下:
Struct {
byte Version[2];
bute random[46];
}12345
master secrect的生成算法简述如下:
Master_key = PRF(premaster_secret, “master secrect”, 随机数1+随机数2)
其中PRF是一个随机函数,定义如下:
PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)123456
从上式可以看出,把premaster_key赋值给secret,”master key”赋值给label,浏览器和服务器端的两个随机数做种子就能确定地求出一个48位长的随机数。 而master secrect包含了六部分内容,分别是用于校验内容一致性的密钥,用于对称内容加解密的密钥,以及初始化向量(用于CBC模式),客户端和服务端各一份。 至此,浏览器侧的密钥已经完成协商。
b ≡a^i mod p (0≤i ≤p-1)1
则称i是b的以a为底的模p的离散对数。
理解这两个概念,dh算法就非常简单了,示例如下: 假设client和server需要协商密钥,p=2579,则本原根a = 2。 1. Client选择随机数Kc = 123做为自己的私钥,计算 Yc = a^Kc mod p = 2^123 mod 2579 = 2400,把Yc作为公钥发送给server。 2. Server选择随机数 Ks = 293作为私钥,计算Ys = a^Ks mod p = 2^293 mod 2579 = 968,把Ys作为公钥发送给client。 3. Client计算共享密钥:secrect = Ys^(kc ) mod (p)= 968^123 mod ( 2579) = 434 4. Server计算共享密钥:secrect = Yc^(K_s ) mod (p)= 2400^293 mod (2579) = 434
上述公式中的,Y_s,Y_c,P, a, 都是公开信息,可以被中间者查看,只有K_(s,) K_c作为私钥没有公开,当私钥较小时,通过穷举攻击能够计算出共享密钥,但是当私钥非常大时,穷举攻击肯定是不可行的。 DH算法有一个比较大的缺陷就是需要提供足够大的私钥来保证安全性,所以比较消耗CPU计算资源。ECC椭圆曲线算术能够很好的解决这个问题,224位的密钥长度就能达到RSA2048位的安全强度。 ECC的曲线公式描述的其实不是椭圆,只是跟椭圆曲线周长公式形似才叫椭圆曲线加密算术。ECC涉及到了有限域、群等近世代数的多个概念,就不做详细介绍了。 ECC安全性依赖于这样一个事实:
P = kQ, 已知k, Q求出P相对简单,但是已知P和Q求出k却非常困难。1
上式看起来非常简单,但有如下约束条件: 1. Q是一个非常大的质数,p, k, q都是椭圆曲线有限域上的离散点。 2. 有限域定义了自己的加法和乘法法则,即使kQ的运算也非常复杂。
ECC应用于Diffie-Hellman密钥交换过程如下:
1. 定义一个满足椭圆方程的有限域,即挑选p, a, b满足如下方程:y^2 mod p=(x^3+ax+b) mod p
2. 挑选基点G = (x, y),G的阶为n。n为满足nG = 0的最小正整数。
3. Client选择私钥K_(c ) (0 < K_(c
4. server选择私钥K_(s )并产生公钥Y_s = K_s × G
5. client计算共享密钥K = K_c × Y_s ,server端计算共享密钥 K_s × Y_c ,这两者的结果是一样的,因为:
K_c × Y_s = K_c × (K_(s )× G) = K_s × ( K_(c )× G) = K_s × Y_c1
由上面描述可知,只要确定p, a, b就能确定一条有限域上的椭圆曲线,由于不是所有的椭圆曲线都能够用于加密,所以p, a, b的选取非常讲究,直接关系曲线的安全性和计算速度。 Openssl实现的,也是FIPS推荐的256位素数域上的椭圆曲线参数定义如下:
质数p = 115792089210356248762697446949407573530086143415290314195533631308867097853951阶n = 115792089210356248762697446949407573529996955224135760342422259061068512044369 SEED = c49d3608 86e70493 6a6678e1 139d26b7 819f7e90
c = 7efba166 2985be94 03cb055c 75d4f7e0 ce8d84a9 c5114abcaf317768 0104fa0d
椭圆曲线的系数a = 0椭圆曲线的系统b = 5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f63bce3c3e 27d2604b
基点G x = 6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0f4a13945 d898c296
基点G y = 4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ececbb64068 37bf51f5123456789
简单介绍了ECC和DH算法的数学原理,我们看下ECDHE在TLS握手过程中的应用。 相比RSA,ECDHE需要多发送一个server_key_exchange的握手消息才能完成密钥协商。 同样以TLS1.2为例,简单描述一下过程: 1. 浏览器发送client_hello,包含一个随机数random1,同时需要有2个扩展: a) Elliptic_curves:客户端支持的曲线类型和有限域参数。现在使用最多的是256位的素数域,参数定义如上节所述。 b) Ec_point_formats:支持的曲线点格式,默认都是uncompressed。 2, 服务端回复server_hello,包含一个随机数random2及ECC扩展。 3, 服务端回复certificate,携带了证书公钥。 4, 服务端生成ECDH临时公钥,同时回复server_key_exchange,包含三部分重要内容: a) ECC相关的参数。 b) ECDH临时公钥。 c) ECC参数和公钥生成的签名值,用于客户端校验。 5, 浏览器接收server_key_exchange之后,使用证书公钥进行签名解密和校验,获取服务器端的ECDH临时公钥,生成会话所需要的共享密钥。 至此,浏览器端完成了密钥协商。 6, 浏览器生成ECDH临时公钥和client_key_exchange消息,跟RSA密钥协商不同的是,这个消息不需要加密了。 7, 服务器处理client_key_exchang消息,获取客户端ECDH临时公钥。 8, 服务器生成会话所需要的共享密钥。 9, Server端密钥协商过程结束。 图示如下:
非对称密钥交换过程结束之后就得出了本次会话需要使用的对称密钥。对称加密又分为两种模式:流式加密和分组加密。流式加密现在常用的就是RC4,不过RC4已经不再安全,微软也建议网站尽量不要使用RC4流式加密。 一种新的替代RC4的流式加密算法叫ChaCha20,它是google推出的速度更快,更安全的加密算法。目前已经被android和chrome采 用,也编译进了google的开源openssl分支—boring ssl,并且nginx 1.7.4也支持编译boringssl。 分组加密以前常用的模式是AES-CBC,但是CBC已经被证明容易遭受BEAST和LUCKY13攻击。目前建议使用的分组加密模式是AES-GCM,不过它的缺点是计算量大,性能和电量消耗都比较高,不适用于移动电话和平板电脑。
身份认证主要涉及到PKI和数字证书。通常来讲PKI(公钥基础设施)包含如下部分:
这里有几点需要说明: 1. 数字签名签发和校验使用的密钥对是CA自己的公私密钥,跟证书申请者提交的公钥没有关系。 2. 数字签名的签发过程跟公钥加密的过程刚好相反,即是用私钥加密,公钥解密。 3. 现在大的CA都会有证书链,证书链的好处一是安全,保持根CA的私钥离线使用。第二个好处是方便部署和撤销,即如果证书出现问题,只需要撤销相应级别的证书,根证书依然安全。 4. 根CA证书都是自签名,即用自己的公钥和私钥完成了签名的制作和验证。而证书链上的证书签名都是使用上一级证书的密钥对完成签名和验证的。 5. 怎样获取根CA和多级CA的密钥对?它们是否可信?当然可信,因为这些厂商跟浏览器和操作系统都有合作,它们的公钥都默认装到了浏览器或者操作系统环境里。比如firefox就自己维护了一个可信任的CA列表,而chrome和IE使用的是操作系统的CA列表。
这部分内容比较好理解,跟平时的md5签名类似,只不过安全要求要高很多。openssl现在使用的完整性校验算法有两种:MD5或者SHA。由于 MD5在实际应用中存在冲突的可能性比较大,所以尽量别采用MD5来验证内容一致性。SHA也不能使用SHA0和SHA1,中国山东大学的王小云教授在 2005年就宣布破解了SHA-1完整版算法。 微软和google都已经宣布16年及17年之后不再支持sha1签名证书。
HTTPS目前唯一的问题就是它还没有得到大规模应用,受到的关注和研究都比较少。至于使用成本和额外开销,完全不用太过担心。 一般来讲,使用HTTPS前大家可能会非常关注如下问题: 1. 证书费用以及更新维护。大家觉得申请证书很麻烦,证书也很贵,可是证书其实一点都不贵,便宜的一年几十块钱,最多也就几百。而且现在也有了免费的证书机构,比如著名的mozilla发起的免费证书项目:let’s encrypt(https://letsencrypt.org/)就支持免费证书安装和自动更新。这个项目将于今年中旬投入正式使用。 数字证书的费用其实也不高,对于中小网站可以使用便宜甚至免费的数字证书服务(可能存在安全隐患),像著名的verisign公司的证书一般也就几千到几 万块一年不等。当然如果公司对证书的需求比较大,定制性要求高,可以建立自己的CA站点,比如google,能够随意签发google相关证书。 2. HTTPS降低用户访问速度。HTTPS对速度会有一定程度的降低,但是只要经过合理优化和部署,HTTPS对速度的影响完全可以接受。在很多场景下,HTTPS速度完全不逊于HTTP,如果使用SPDY,HTTPS的速度甚至还要比HTTP快。 大家现在使用百度HTTPS安全搜索,有感觉到慢吗? 3. HTTPS消耗CPU资源,需要增加大量机器。前面介绍过非对称密钥交换,这是消耗CPU计算资源的大户,此外,对称加解密,也需要CPU的计算。 同样地,只要合理优化,HTTPS的机器成本也不会明显增加。对于中小网站,完全不需要增加机器也能满足性能需求。
国外的大型互联网公司很多已经启用了全站HTTPS,这也是未来互联网的趋势。国内的大型互联网并没有全站部署HTTPS,只是在一些涉及账户或者 交易的子页面/子请求上启用了HTTPS。百度搜索首次全站部署HTTPS,对国内互联网的全站HTTPS进程必将有着巨大的推动作用。 目前互联网上关于HTTPS的中文资料比较少,本文着重介绍了HTTPS协议涉及到的重要知识点和平时不太容易理解的盲区,希望能对大家理解HTTPS协 议有帮助。百度HTTPS性能优化涉及到大量内容,从前端页面、后端架构、协议特性、加密算法、流量调度、架构和运维、安全防攻击等方面都做了大量工作。 本系列的文章将一一进行介绍。