HTTPS碎片信息

本文是我了解HTTPS过程中记录的一些碎片信息。

基本概念

  • 对称密钥加密系统:编/解码使用相同密钥的算法
  • 不对称密钥加密系统:编/解码使用不同密钥的算法
  • 公开密钥加密系统:一种能够使百万计算机便携地发送机密报文的系统
  • 数字签名:用来验证报文未被伪造或篡改的校验和
  • 数字证书:由一个可信的组织验证和签发的识别信息

对称密钥加密技术

保持密钥的机密状态是很重要的。在很多情况下,编/解码算法都是众所周知的,密钥是唯一保密的东西。

好的加密算法会迫使攻击者尝遍每一个可能的密钥,才能破解代码。

可用密钥值的数量取决于密钥的位数,以及可能的密钥中有多少位是有效的。有些加密技术中只有部分密钥是有效的。

枚举攻击:用暴力去尝试所有的密钥值称为枚举攻击(enumeration attack)。

对称密钥加密技术的痛点之一:发送者和接收者在互相对话之前,一定要有一个共享的保密密钥。如果有N个节点,每个节点都要和其他所有N-1个节点进行安全对话,总共大概会有N*N个保密密钥,这几乎无法管理。

常见的对称加密算法有DES、3DES、AES、Blowfish、IDEA、RC5、RC6。

公开密钥加密技术

公开密钥加密技术没有为每对主机使用单独的加密/解密密钥,而是使用了两个非对称密钥:一个用来对主机报文编码,另一个用来对主机报文解码。

编码密钥是众所周知的,但是解码密钥只能为报文的目标主机所持有。

P.S: 公开密钥加密技术似乎只适合「多对一」通信。

公开密钥加密一般都是非对称的,即加密密钥和解密密钥不同。共同挑战是,要确保即便有人拥有了下面线索,也无法计算出保密的私有密钥:

  • 公开密钥(是公有的,所有人都可以获得)
  • 一小片拦截下来的密文(可通过对网络的嗅探获取)
  • 一条报文与之相关的密文(对任意一段文本运行加密器就可以得到)

RSA

RSA是一个满足了所有上述条件的公开密钥加密系统,破解RSA系统的私密钥匙的困难程度相当于对一个极大的数进行质因数分解,这是计算机科学中最困难的问题之一。

关于更多RSA的内容,参考:RSA算法原理(一)RSA算法原理(二)

数字签名

数字签名是附加在报文上的特殊加密校验码,即所谓的校验和。

数字签名算法的输入是啥呢?报文消息?No!数字签名算法对消息的长度和格式是有要求的,要求数据满足一定的条件。所以不能直接使用报文消息作为输入。一般策略是是对报文消息先进行哈希,得到固定长度的哈希值,然后在对哈希值进行签名。如下图:

QQ20170227-2@2x.png
  • 节点A将变长报文进行哈希,生成定长的消息摘要
  • 节点A对摘要应用了一个签名函数,该函数会将用户的私有密钥作为参数,输出校验和
  • 签名被附着在报文的末尾,一并发送给节点B
  • 接收端B对签名进行逆向处理(使用公开密钥),将得到的消息摘要与自己计算得到的消息摘要进行对比,进而判断报文是否被篡改

显然,签名一般是在非对称公开加密技术基础上建立的,签名作者持有私钥,签名接收者持有公钥。

综上,签名的作用有两点:

  • 证明是作者编写了这条报文,因为只有作者持有的密钥才能生成校验和
  • 签名可以防止报文被篡改,攻击者若拦截报文,然后对之进行修改,然而校验和无法匹配,这会在接收者那里被识破

P.S: 消息摘要是哈希算法通过哈希处理得到的,哈希算法的安全性从很大程度上决定了数字签名的安全性,所谓哈希算法的安全性,在这里指的是,如果消息报文被篡改了,那么篡改后的摘要和篡改前的摘要必须不同。最近Google宣布实现了对著名的哈希算法SHA-1的碰撞,详见这里

数字证书

数字证书是由证书颁发机构签发的,像身份证一样,不易伪造。包括如下内容:

  • 证书序列号
  • 证书签名算法
  • 证书颁发者
  • 有效期
  • 公开密钥
  • 证书签发机构的数字签名
  • 等等

P.S: 特别需要注意的是「证书签发机构的数字签名」,浏览器收到某个Web服务器的证书时,会对签名颁发机构的签名进行检查,一般来说,浏览器事先就已经预安装了很多签名颁发机构的证书(含有公开密钥),因此可以对签名进行验证。如果浏览器对签名颁发机构一无所知,浏览器就无法确定是否应该信任该签名颁发机构,它通常会向用户显示一个对话框,看看用户是否相信这个签名发布者,这种签名发布者往往是本地的IT部门或者软件厂商。

P.S: 大多数证书都遵循X.509 v3标准。

基于X.509证书的签名有好几种,包括:

  • Web服务器证书
  • 客户端电子邮件证书
  • 软件代码签名证书
  • 证书颁发机构证书

HTTP的缺点

HTTP主要有三大不足:

  • 通信使用明文(不加密),内容可能会被窃听
  • 不验证通信方的身份,有可能遭到伪装
  • 无法证明报文的完整性,报文可能被篡改

或者参考阮一峰大神的博客SSL/TLS协议运行机制的概述的说法,简称为三大风险:

  • 窃听风险(eavesdropping)
  • 冒充风险(pretending)
  • 篡改风险(tampering)

本文的目的是就是详细阐述这三大问题,以便以后更好地理解HTTPS。

窃听风险与加密

一个重要的事实是:TCP/IP是可能被窃听的网络。TCP/IP协议簇的工作机制,通信内容在所有的通信线路上都有可能遭到窥视:

QQ20170121-0@2x.png

所谓互联网,是由能联通到全世界的网络设备组成的,无论哪里的server和client通信,此线路上的网络设备(包括电缆、计算机、路由器、交换机等)都不可能是个人的私有物,因此根本无法避免某个环节的报文会被窥探。

窃听报文并非难事,只要收集互联网上流动的数据包即可,然后对它们进行解析。

通过加密防止报文被窃听

在应对报文被窃听的对策中,最为普遍的做法是加密技术,加密并不是个陌生的概念,两个重要问题:被加密的对象是啥?采用哪种加密方式?

对内容进行加密

对内容本身进行加密是最容易想到的,加密后的内容,即便报文被捕获,没有解密秘钥,拿到的也是一堆乱码。此处的「内容」指的是啥?众所周知,HTTP message有三大组成部分:起始行、首部、报文主体,对内容加密的这种方式,被加密对象是哪一种呢?

一般来说,不会对起始行和首部进行加密。为啥呢?根据我的理解,一方面是意义不大,另一方面首部和起始行信息不光是给接收端看的,也是给沿路中的各种代理看的,加密后的首部和起始行叫人家怎么看?因此,加密对象一般是报文主体或者部分报文主体(敏感内容)。

诚然,为了做到有效的内容加密,前提是要求client和server同时具备加密和解密机制。

内容加密的相关算法

另一个问题,对内容加密的方式中,一般采用何种加密呢?加密算法太多了,这里就不展开了…

对内容加密的不足

只要加密算法足够安全,并且密钥被保护得当,对内容加密能够避免报文主体的敏感内容被监听,但是仍然无法避免内容被篡改。

这个也容易理解,在传输过程中,窃听者虽然读不懂报文的内容的意义,但是仍然可以修改报文内容,譬如把报文的主体内容给清掉,进而对接收者进行误导。

对信道加密

相对于内容加密,「信道加密」这个概念比较生僻一些,内容是比较容易理解的,那么,何为「信道」呢?

我们知道,网络协议是一层层的,HTTP建立在TCP的基础上,TCP建立在IP的基础上。对于HTTP协议来说,所谓「信道」其实是TCP层(类似,TCP报文的信道是IP层),如果TCP层的通信是安全的,那么我们谈论HTTP加密似乎就没啥意义了。因此,所谓信道加密,是指HTTP所依赖的更底层协议被加密。

这里所指的信道加密和SSL/TLS有关,搁在后面再讲。

P.S: 对「信道」和「信道加密」的阐述,只是我的理解,可能是错的。

冒充风险与身份认证

另一个重要的事实是:任何人都可以发起请求。

HTTP协议并没有要求对通信方进行确认,server只要接收到request,就会给出一个相应的response,因此会存在如下隐患:

  • 无法保证request发送到了目标server,有可能接收者是伪装的server
  • 无法保证response是被正确的client接收,有可能接收者是伪装的client
  • 无法确定正在通信的对方是否具备访问权限,因为某些Web服务器上保存着重要的信息,只想发给具备某种特定权限的client
  • 无法避免无意义的request涌入,既无法阻止海量请求下的DoS攻击(Denial of Service,拒绝服务攻击)

通过证书验证身份

身份认证可以解决这个问题,SSL/TLS提供了这种服务,详见之后的博客。

篡改风险与完整性保护

上文已经提到,通过内容加密方式,可以避免报文敏感信息被窃听,但是无法避免报文被篡改。譬如,request或response在传输途中,遭受攻击者拦截并篡改内容,这种攻击行为被称为中间人攻击(Man-In-The-Middle attack,MITM attack)。

什么是完整性保护呢?所谓完整性并不是指「报文没有受损」,而是指报文的准确度;换句话说,如果无法证明报文的完整性,那么意味着无法判断报文信息是否准确。

与窃听风险、冒充风险不同,篡改风险的应对措施比较多,根据《HTTP权威指南》的说法,至少包括:基本认证、摘要认证,以及数字签名。

在HTTP应用中,一种常见的策略是使用散列值校验,简单来说,发送方使用散列值算法(最常见的有MD5、SHA-1,又被称为摘要算法),对消息进行哈希,得到固定长度的哈希值(是谓「摘要」),将该哈希值与消息一起传给对方,对方在收到message后,也使用约定的散列值算法对报文进行哈希,再与发送方的哈希值进行对比,如果不一致,则说明报文已被篡改,不安全。

然而,这是会存在问题的,一方面是MD5、SHA-1不再安全,另一方面「摘要」本身也是可以被篡改的。

更好的做法是,对摘要本身也进行保护,这个过程一般被称为数字签名,上文已经对数字签名有所阐述,这里就不再赘述。

初步了解SSL/TLS

HTTPS(Hypertext Transfer Protocol Secure)被称为「HTTP over TLS」或「HTTP over SSL」或「HTTP Secure」。它并不是应用层的一种新协议,只是HTTP通信接口部分用SSL或TLS协议代替而已。通常,HTTP直接和TCP通信,当使用SSL/TLS时,则演变为先和SSL/TLS通信,再由SSL/TLS和TCP通信,简单来说,HTTPS在HTTP和TCP之间隔了一层SSL/TLS(通常被称为安全层)。

上文谈到了HTTP存在的三个重大毛病,SSL/TLS解决了三个毛病的哪一个呢?答案是:所有。

因此,此处引用《图解HTTP》对HTTPS的总结:

HTTPS = HTTP + 加密 + 认证 + 完整性保护。

简单来说,建立在SSL/TLS协议之上,HTTP具备加密、认证和完整性保护这些特点。本文旨在理清SSL/TLS是如何实现加密、认证和完整性保护的。

首先一个必要的任务是搞清楚SSL和TLS的关系。SSL是网景公司推出的,3.0版本后,被IETF标准化,写入RFC,是谓TLS。下表是对它们的说明:

版本 发布时间 RFC 说明
SSL 1.0 从未公开过,因为存在严重的安全漏洞
SSL 2.0 1995年2月 因为存在数个严重的安全漏洞而被摈弃
SSL 3.0 1996年 无(后来作为历史文献被添加到RFC中,是谓RFC6101 2014年10月,Google发现在SSL 3.0中发现设计缺陷,建议禁用此一协议,后续Microsoft、Mozilla跟进
TLS 1.0 1999年1月 RFC2246 从技术上讲,TLS 1.0与SSL 3.0的差异非常微小
TLS 1.1 2006年4月 RFC4346
TLS 1.2 2008年8月 RFC5246 现在主流
TLS 1.3 草案阶段

可见,SSL已是历史了;但是大家仍然习惯使用术语SSL指代SSL或TLS。

对于SSL/TLS,最重要的内容莫过于其握手过程的分析,以后专门开辟博客阐述吧。

各种劫持与攻击

经常看到或者听到一些与安全相关的名词,譬如DNS劫持、HTTP劫持、DDoS攻击等,这一部分旨在对这些名词进行简单概述:

HTTP报文劫持

所谓HTTP报文劫持,指的是HTTP报文在server和client的传输过程中被修改的现象,这是运营商(ISP)比较喜欢做的事情,凑不要脸!HTTP劫持主要发生在Web网页中,故而又被称为网页注入。简单来说,运营商常常在server发往client的HTTP报文中插入一段代码,这段代码通常与广告信息有关。相当于你让某个商店邮寄一包东西到你家,你收到的包裹里却有运营商附加的一坨屎。

HTTPS能解决HTTP报文劫持的问题吗?

显然可以,SSL的完整性保护确保了这件事情不会发生。

DNS劫持

DNS(域名系统)的作用是把网络地址对应到能够识别的IP地址,以便设备能够进一步通信,传递网址和内容等。DNS劫持的实质是把client的域名劫持指向到非正常的IP地址。

P.S: DNS劫持是流量劫持的一种,又称域名劫持,或称DNS钓鱼攻击。

P.P.S: 除了DNS劫持,流量劫持还包括哪些呢?

HTTPS能解决DNS劫持的问题吗?

答案是一般可以,但没有什么事情是绝对的。Server与client建立HTTPS通信的前提是server持有受信任的合法证书;换句话说,如果被劫持到的目标server搞到一张假的受信任的证书,又或者它自己签发一个证书,并且client信任了该证书,那么DNS攻击依然存在。

总之,HTTPS下的DNS攻击门槛非常高,要么搞定CA机构,要么让用户信任自签发的证书。从另外一个角度来看,作为用户,我们不应该轻易相信别人自签发的证书,根据我的理解,这一点在网页端的问题要比移动客户端严重得多。

P.S: 知乎的这个话题下有些比较好的说明。

P.S: DNS劫持也常常发生在路由器中,譬如被人诟病的小米路由器。

运营商/路由器缓存造成的劫持

上述的HTTP报文劫持和DNS劫持都被统称为网络劫持,除了这两种,还有一种常见的劫持:运营商或者路由器无脑的缓存。

点评大神周辉我司内部分享时举了一个相关例子:

tree-pics@2x.png

如上图所示,不同用户居然获取到同一个用户的个人信息,这几个用户连接的都是上海地铁上的花生wifi,最后定位到的原因是花生wifi服务商对HTTP response进行了缓存,缓存的key自然是HTTP request,但是在对request处理时居然将参数给去掉了…

DDoS攻击

这种攻击比较简单了,一般情况下的SSL/TLS通信模式是单向认证,并不能解决DDoS问题…

HTTPS与实践

本文记录我的一些HTTPS实践经历或体会。

P.S: 然而,到目前为止,其实没啥近距离的HTTPS实践机会…

ATS

ATS并不等价于「所有App的HTTP API都得使用HTTPS」,它比后者要求得更多,这里有详细说明。简单来说:

  • 默认情况下,server的TLS版本得是1.2+
  • 对此加密算法得是AES-128或者AES-256级别的
  • 等等

处理业务时,遇到一个case:外网 https://api.guanaitong.com 的web页面在我们app内不能访问,经查,发现是server的TLS版本过低(TLS 1.0),给他们的server反馈后,已解决…可惜当时没留下截图,一个难得的case。

如何知道server支持的TLS的版本呢?

可以使用openssl工具,譬如openssl s_client -connect api.guanaitong.com:443 -tls1_2,参考自:How can I verify if TLS 1.2 is supported on a remote Web server from the RHEL/CentOS shell?

P.S: macOS默认已安装openssl工具,但是版本比较老(低于v1.0),使用-tls1_2选项会有问题,需要升级…

如何知道server对ATS的支持情况呢?

使用另一个工具nscurl,譬如:

nscurl --ats-diagnostics --verbose https://api.guanaitong.com