深入理解 Web 安全:中间人攻击

独家号 Web安全实验室 作者 朱英达 原文链接

对于围绕着web客户端的攻击,本篇简要谈谈最后一种攻击方式,所谓的“中间人攻击”。

对于之前所谈到的三种常见的,围绕着web客户端的攻击方式,可以去看看我之前的博客:

XSS漏洞

CSRF漏洞

ClickJacking漏洞

中间人攻击,也被称为浏览器劫持、web劫持。这是一种很特别的攻击方式,在很多经典的web安全方面的技术书籍中都很少提到,然而攻击的破坏力却丝毫不亚于以上所提到的任何一种web安全漏洞。

对于这种攻击方式,简单地说,就是黑客通过各种各样的技术手段,在服务端发送出的http/html报文与显示屏呈现出的web页面之间做了一些手脚,篡改网页的部分或全部内容,从而改变用户在浏览器视窗中看到的内容。

这种攻击方式可以达到的目的非常多,常见的是往web页面里塞入一些广告厂商的DOM元素,也有可能直接把网络请求劫持到另外一台服务器,很可能是个钓鱼站。

从实现漏洞实现的原理上面主要可以分为两类:

1. 在网络报文传输过程中对其截获、篡改。

2. 在客户端浏览器发送http请求之前或得到httpResponse之后对数据进行篡改。

我为什么要这样分类呢?原因是这两种不同的截获方式对应的防御手段是不同的。

先说第一种,对于http协议来说,无论是request报文还是response报文全部都是明文传输的,因此不难理解的是当你在浏览器中输入url敲下回车的那一刻,http网络请求要经历很多层路由、交换机才能到达服务器所在的那台物理机的80端口(浏览器默认会访问)。

无论多么遥远,服务器接收到你的请求之后,返回的http response依然要经历同样的一层又一层复杂的网络环境最终传输到浏览器并开始渲染和解析。

由于http协议是明文传输,所以中间的每一层都有可能被黑客设下埋伏,修改报文内容即可达到中间人劫持的目的。

对于这种类型的中间人攻击,是有很成熟的解决方案的,简言之就是上https。

什么是https协议?简单地说,就是在TCP(传输层)HTTP(应用层)之间加入了一个名为TLS的协议,从而提供了一套完整的内容加密及相关问题的解决方案

有关TLS的具体实现原理,在学习https之初我查阅了很多相关的资料和博客,大量的陌生英文缩写术语把我搞的一头雾水,在写此篇博客之前我也犹豫再三,终于还是下定决心想要自己来谈一谈https协议,力求让更多的人话费更少的成本理解TLS是如何保证http报文安全传输的。

简单地说,一次https网络请求在建立开始阶段具有以下的一个“握手”流程:

首先,客户端向服务端发起一个基于https协议的网络请求,这相当于告诉它:“我希望得到一个安全加密的网页,你可别直接把明文扔过来!”

服务端接收到这个网络请求后,了解到客户端的提出的这种加密的诉求,于是先把一个公钥和网站的https证书发送给客户端。

客户端随后要做两件事,一是验证证书的合法性与时效性,如果颁发证书的机构客户端这边不承认或者证书中标明的过期时间已经过了,这都会导致客户端浏览器报出那个红叉子,chrome浏览器还会直接拦截掉这个请求,除非用户点详情->继续,否则不会与该网站的服务器进行后续沟通,这相当于一个强交互的提醒,告诉用户“我拿到的证书有问题,这网站可能是个冒牌货,你要看仔细了!”

如果以上两步验证无误,那么客户端会先生成一个随机秘钥,利用刚刚拿到的公钥给自己要访问的url+这个随机秘钥进行加密,把密文再次发往服务端。

当服务端收到客户端传过来的密文之后,会通过自己手里持有的一个私钥对密文进行解密。注意,这里提到的私钥和刚刚的公钥是一对儿秘钥,这是一个典型的非对称加密,加密和解密分别使用两把不同的钥匙,这也保证了在此场景下的安全性。

此时,服务端要将真正的html网页文本发给你了,它会利用解密得到的随机秘钥对网页文本内容进行加密,将密文发给客户端。

客户端拿到真正的html报文之后,就用自己刚才生成的那个随机秘钥进行解密,然后就得到了跟普通http请求时一样的一个网页文本了,在这之后就像往常那样解析、渲染、加载更多资源……

对于真正要传输的html文本,实际上是使用刚刚提到的这个随机秘钥进行了一次对称加密,因为上锁和开锁的钥匙实际上是一模一样的。

有关TLS更详细的技术细节,推荐大家看看屈屈的这篇博客,个人认为算是讲得比较详细的一篇。

实际上,前面的大费周章,都是为了将这个随机生成的对称加密秘钥同步给服务端,双方手里持有该秘钥之后就可以使用对称加密的思路保护传输的内容本身了。

需要说明的一点是,我讲的这个TLS握手流程是通过false start优化过的一个抢跑方式的TLS握手,只需要一次RTT握手即可开始传输数据。有些朋友在网上的很多资料中查阅时可能会看到与这个流程不一样的版本,这里并不是谁的文章写错了。

https协议拥有这样一套非常完善和成熟的解决方案,基本上杜绝了99%以上的存在于传输过程当中的中间人劫持问题,因为url的内容也是密文发送的,所以中间人劫持到了一段加密过后的报文,只能知道这可能是一串https协议的密文,而至于其url指向谁,参数是什么,一无所知,很难进行篡改和劫持。

第二种类型的中间人劫持相对少见,但我也遇到过。

其主要的实现原理是在客户端用户的操作系统中植入木马,就windows平台而言,c++的hook玩好了也能做不少的事情。

我曾亲身经历过的一个情况是,曾经在我的一台PC设备(win7系统)上面,被瑞星的一些捆绑插件莫名植入了木马,唯独对360浏览器进行劫持,他不是每次毕现,但时常会发生我打开360浏览器的一瞬间多弹出一个瑞星的导航页。

包括一些浏览器插件,很有可能通过各种各样的手段做埋伏,对于这种攻击来说,https协议无能为力,我们唯一能做的是加强web页面自身对客户端环境的嗅探、监控和上报机制,尽量做到对于被劫持的情况能够有所感知。

web作为一种客户端的存在,其毋庸置疑是最特殊的一种客户端意识形态,原因是没有任何一个客户端应用像web一样高度依赖于服务端的渲染、数据的交互。这给web带来了比传统客户端更强的灵活性,但也在安全性方面造成了很大的隐患。

因此要谈web的安全问题,必然将其分为两部分:围绕着web客户端的攻击手段围绕着web服务器的攻击手段

截止到本文,针对web客户端可以进行的主要攻击手段都以做了一个浅显的介绍,之后一方面会考虑写一些对于这四种攻击手段的进阶研究,另一方面会写一些web服务端安全漏洞相关的话题。

如果对web安全方面感兴趣,可以关注下我最近在搞的一个开源项目veneno,项目主张以Node.js来进行web安全方面自动化攻击、防御的一些实践。

开发者头条

程序员分享平台