相信很多人都试过这样的经历,浏览一个正常的网站时,右下突然角弹出一堆小广告,而且这些广告的内容和你浏览的网站格格不入:
前几天还有某微博用户爆料访问github时居然也有广告:
又或者,你有没有试过因为不小心输错了某个网站的网址,出来一堆不堪入目的广告内容?
我今天还特意在家里试了一把,故意输入一个乱七八糟的网址,出来的页面让我无语,各种小广告,而且连续故意输错几个网址,都是这样:
上面说的几个事情,未必但很有可能就是运营商DNS劫持。事实上,运营商劫持几乎到了明目张胆的地步,尤其是一些N级小电信运营商。对运营商劫持的一些实际例子的危害,感兴趣可以看看这篇文章
什么是DNS劫持
DNS劫持的概念我就不抄书本了,大致原理其实非常简单。
说到DNS,肯定跟域名有关系。我们都知道在浏览器输入一个网址,首先要经历DNS查询,攻击方通过劫持DNS,给你返回一个假的服务器IP(攻击方的服务器),这时候你访问的就不是你要的服务器了。而攻击者为了更好地伪装,往往充当一个“代理”角色,把你的请求转发给真实地服务器,真实服务器把内容返回到攻击者,攻击者在这些内容里面做些手脚,比如放进去一些广告、脚本等等,再发送给访问者。访问者看到的内容便是被改动过的了。
DNS劫持的方法有很多,DNS服务器被黑,直接黑进你的电脑里改hosts文件等等,或者运营商偷鸡摸狗在DNS上搞鬼都是很正常的事……
运营商DNS劫持,其实大部分时候危害不大,最多的就是想钱想疯了,插入些小广告。但是如果是黑客恶意的劫持,那危害就大了,因为页面访客访问的内容是攻击者控制、篡改了的,而且往往非常隐蔽不好发现,web用户分分钟任人宰割。
HTTP的安全缺陷
之所以DNS一旦被劫持用户就变成任人宰割的小鸟,根本原因在于HTTP协议本身的一些安全缺陷。
- 明文传输
http协议本身不具备加密功能,通信过程中只要数据包被攻击者抓取,通信内容就可以直接被读取。例如你随便连了一个没有密码的WiFi,以为白捡了免费的网,殊不知你的上网内容很可能早就被被人看到了,如果你访问的网站没有使用HTTPS,那么你在上面输入的用户名、密码、银行卡信息可能已经被监听者收入囊中。
监听的过程其实就是网络抓包过程,什么?搞技术的不知道什么是抓包?我就不说wireshark、sniffer这些了,fiddler你总听说过了吧?
- 不验证身份
当你访问http://www.qq.com
时,其实你是保证不了收到的内容一定是从腾讯的服务器来的。一个很简单的比方:攻击者克隆了一个一模一样的腾讯网,然后因为某种原因(DNS劫持),你访问腾讯网时的IP被解析到了这个克隆网站,这时候你访问的就是这个克隆网站。
同理,访问者的身份也是很容易伪装的,服务器也不能确定通信的对方一定是合法的访问者。
- 没有数据完整性校验
在HTTP请求或响应发送出去之后,到对方接收到信息之前,内容遭到攻击者的篡改,对方是没有办法获悉的。换句话说,没有任何办法可以确认,发送出去的消息和接收到得消息前后是一致的。
为了保证内容的一致,有些网站使用MD5和SHA-1等散列值校验方法,确保用户收到的内容是正确的。
例如某下载网站提供文件的以下相关数据,确保用户下载的文件没有被修改。用户只要在下载了文件之后自行计算文件的散列值,并和网站提供的散列值对比,从而得知文件有没有被修改过。
但是,这种检查方法取决于用户本人的亲自检查,浏览器无法自动帮助用户检查;再者,MD5本身被改写的话,用户是没有办法意识到的。
HTTPS
要解决上面的三个问题,需要引入三个机制:
1、 内容加密 让监听者拿到消息也看不懂
2、 证书 用一个权威的机构(CA)和证书来证明通信双方的身份(CA的概念会在后面解释)
3、 完整性校验
为了解决这三个问题,引入了HTTPS。
披着SSL外衣的HTTP
HTTPS全称是Hyper Text Transfer Protocol over Secure Socket Layer,它并不是一个新的协议,其本质上是在HTTP和TCP之间加了一层SSL/TLS协议。 通常,HTTP是直接和TCP通信的。
当使用了SSL时,就变成了HTTP先和SSL通信,再由SSL和TCP通信。
前面所说的加密
、证书
、完整性校验
便由SSL来完成。
加密技术
讨论SSL之前,有必要了解一下加密方法。SSL采用了对称密钥加密和非对称密钥加密混合的加密处理方式。对于这两种加密算法,本文不做过多阐述,只简单介绍,因为这里面的内容可以写一本书了。
对称密钥加密
对称密钥加密也叫共享密钥加密。所谓对称,也就是加密和解密双方都使用同一把钥匙。
既然双方密钥一样,所以存在密钥发送过程,发送途中只要攻击者也拿到这个密钥,那么就可以随时破解通信内容了。
既然发送密钥有被窃听的风险,但不发送吧对方又不能解密。所以,安全地发送密钥给对方,就成了通信的关键。
非对称密钥加密
非对称密钥加密也叫公开密钥加密。这种加密方式有两把密钥,一把是私有密钥(私钥),一把是公开密钥(公钥)。公钥可以随意发布,谁都可以拿到,并用它来加密内容,这个加密内容只有私钥可以解开,而私钥是不公开的。
使用公开密钥加密方式,发送密文的一方使用对方提供的公钥加密内容,这个加密内容只有对方收到后,使用私钥才能解密。利用公钥和密文进行解密就目前的技术来看还不太现实,所以这种方式目前是非常安全的。
常见的非对称加密算法有RSA等,感兴趣的可以看阮老师的RSA算法原理(一)和RSA算法原理(二)。
混合加密机制
上面说的两种加密方法,对称加密过程相对简单,但是密钥传输不当的话安全性没法保证;非对称加密过程安全,但是实现过程会更复杂、消耗更多时间,效率会低。
所以HTTPS采用了两者并用的加密机制,这里面包含两步:
1、 使用非对称密钥加密方法来传输对称密钥
2、 使用第一步中传输的对称密钥来进行消息加密
第一步完成后,对称密钥(上图黄色的钥匙)没有第三方可以获取到,保证了加密秘钥不会被第三方窃取;同时第二步使用对称密钥使得加密解密过程更加快速。
证书
确保了内容加密之后,通信实际还是不安全的,因为,一方面客户端收到公钥,但还是无法证明收到的公钥就是它预想的那台服务器发行的公钥。
因为坏人自己可以生成公钥/私钥冒充服务器端发给客户端,然后中间窃取消息再用真正的公钥私钥转发给真正的服务端(中间人攻击),这样就不安全了。
说白了,搞不好和你加密来解密去的对方到头来就是一个攻击者。
为了解决这个问题,SSL协议引入了数字证书认证机构(CA) + 数字证书的机制。这里简单解释下两个名词:
CA:Certificate Authority,是证书的签发机构,是负责签发证书、认证证书、管理已颁发证书的机关。简单的说,CA是一个得到社会普遍认同的权威机构,通信过程中,只要CA告诉你对方是合法的,那么就是合法的,同时对方提供的公开密钥也是没有经过修改替换的。
数字证书:也叫公开密钥证书、证书。数字证书用于实现身份识别和电子信息加密。数字证书中含有密钥对(公钥和私钥)所有者的识别信息,通过验证识别信息的真伪实现对证书持有者身份的认证。
CA认证的过程简述如下:
- CA自己本身有一个对称加密机制,即已生成私钥和公钥。自己留有
CA私钥
,而CA公钥
已经植入大多数浏览器中。 - 服务器生成一对非对称密钥,自己留有
服务器密钥
,把服务器公钥
提交给CA。 - CA使用自己的
CA私钥
向服务器公钥
进行数字签名
(实际就是加密),成为公钥证书
,还给服务器。 - 通信的时候,服务器把
公钥证书
发给客户端。 - 客户端拿到
公钥证书
后,使用步骤1中的CA公钥
对这个公钥证书
进行数字签名
(实际就是解密)。 - 如果签名(解密)成功,就可以得到
服务器公钥
,并且可以确定这个公钥是真实有效的服务器发放的。 - 客户端使用步骤6中得到的
服务器公钥
加密消息,这个消息只有步骤2的服务器密钥
可以解密。
在《图解HTTP》(【日】上野宣著 于均良译)这本书中有个图把这个过程阐述得非常清晰明了:
绿色图标
前面说到,CA公钥
已经植入大多数浏览器中,正是因为这点访问者可以验证服务器及其公钥的真实性,你可以查看你的浏览器中已有的CA密钥:
我们在浏览一些申请了标准正规的证书的网站时,地址栏会有绿色的图标,例如某网站:
绿色图标的初衷是为了提醒用户注意被钓鱼,但是实际情况中用户会不会去关注,就是个问题了。
CA被攻击
试想,当ZF被人收买时,你还会相信ZF吗?
同样地道理,我们相信CA,是建立在CA信用绝对可靠、大家都相信的情况下的。但是,当CA本身遭到攻击,颁布了伪造的证书后,影响就非常大了,例如下面这个例子:
这种情况下,虽然有可将证书无效化的证书吊销列表机制,以及从客户端删除根证书颁发机构的对策,但是距离生效是需要一段的时间的(例如取决于用户是否升级浏览器、是否为系统打补丁),在这段时间内,有多少用户蒙受损失,是难以估量的!
自签名证书
SSL是基于openssl这个开源程序的,其实每个人都可以给自己颁发数字证书,这时候自己就是CA了。当然因为你自己一定是权威的机构,所以你给自己颁发的这个证书是不被浏览器认可的,例如我国某大型电商网站的证书:
客户端证书
前面说的都是服务器证书,用来验证服务器身份的。然而反过来,服务器想要验证客户端真实性的时候,怎么办呢? 其实原理是一样的,这时候就需要客户端证书,整个验证过程和前面的服务器证书验证过程基本一致,这里不再赘述。
客户端证书的一个典型例子:你有去过银行开网银吧?很多银行都会给你一个巨大的“U盘”,让你登陆网银的时候插上去,这个“U盘”里便保存着客户端证书。
完整过程
到这里已经可以梳理出一个HTTPS通信的完整过程。
再次从《图解HTTP》(【日】上野宣著 于均良译)这本中偷来一张神图,解释了仅使用服务器证书时建立HTTPS通信的过程:
客户端和服务器协商加密组件,这里面其实包含了两步: 1) 客户端发起SSL通信,告知服务器客户端支持的加密组件(加密算法、密钥长度)列表等等信息 2) 服务器从上面的加密组件列表中选取,并告知客户端
服务端给客户端发送服务器的
公钥证书
- 客户端从
公钥证书
中取出服务器公钥
用这个公钥加密一个客户端的pre-master secret
- 客户端发送这个加密了得
pre-master secret
给服务器 - 服务器解密
pre-master secret
得到master secret
- 这时候客户端和服务端都有了一个
master secret
,可以把它理解为对称加密密钥,并且这两个对称密钥没有第三者知道,之后的通信内容,就用这对密钥加密就行了。
性能
HTTPS通过使用SSL/TLS,解决了加密、证书、完整性校验等安全问题,同时也带来了明显的性能问题:
1、 SSL握手延迟
在传统的TCP三次握手的基础上,还必须进行SSL通信,至少增加一次RTT,这个时间的消耗有可能是非常大的(例如移动端网络),取决于客户端与服务端通信链路的物理距离和中间节点数量。
2、 加密解密消耗
和明文通信相比,SSL增加了加密和解密过程,这个过程对CPU、内存、时间的消耗也是不可忽视的。
以上两点,是其他条件不变的前提下,从HTTP迁移到HTTPS必然带来的性能问题。为了弥补时间的消耗,很多网站现在已经开始使用SPDY、HTTP/2,篇幅有限,有机会再介绍这两个东西。
再说回DNS劫持
说到这里,为什么HTTPS能够有效的解决DNS劫持,应该就很好解释了。
在域名被劫持的情况下,客户端得到一个攻击者的IP,客户端通过这个IP找到攻击者的服务器,要求建立HTTPS通信,因为攻击者没有真实服务器的证书和私钥,把伪造或自签名的证书提供给客户端,是得不到CA的认可的。
劫持者是可以拿到真实服务器公钥的,所以可以窃取真实服务器发给客户端的内容并解密的,但是他没有真实服务器的私钥,所以即使偷到这个内容,也只能原封不动地传给客户端,乖乖充当一个代理者。如果劫持者对这个内容做了修改,在客户端那里是无法通过校验的,因为只有真实服务器私钥加密的内容,才能在客户端那里被识别。
由此可知,部署和使用HTTPS的过程中,服务器的私钥是非常非常重要的,只有服务器自己能保留和知道,如果泄露了,安全就等同虚设了。
想说但没说的
下面的内容跟HTTPS、SSL密切相关,但是不影响基本原理的理解,感兴趣可以自行去了解:
- 数字签名/数字摘要
- SSL与TLS的关系
- openssl漏洞,例如去年轰动全球的“心脏滴血”(heartbleed)漏洞
- SSLstrip攻击
- 运营商DNS和HTTP劫持的区别