由于目前网络上还没有关于WebSocet各方面介绍与考量十分详尽的文章(当然英文版的RFC除外),这里我说一下那个神奇的Masking Key是做什么的吧。
首先不要把它与IP网络中的子网掩码弄混,绝壁不是一个概念,后者是用来划分子网的, 而前者是考虑到网络安全问题而设计的。
WebSocket协议规范里讲:“为了避免迷惑网络中介(如代理服务器),以及涉及到安全问题,客户端必须mask所有送给服务器的frame。”
不明白怎么回事?没关系,在此之前先了解下网络上针对基础设施的攻击,然后才能明白掩码的设计道理。
针对基础设施的攻击
通过WebSocket协议成为被攻击对象的,除了终端设备之外还有其他部分的web基础设施,比如代理服务器就可能成为攻击的对象。
随着websocket协议被开发出来,一项针对代理服务器的攻击(污染那些广泛部署的缓存代理服务器)实验也开始进行。
一般形式的攻击是跟被攻击者控制的服务器建立连接,并构造一个类似WebSocket握手一样的UPGRADE请求,随后通过UPGRADE建立的连接发送看起来就像GET请求的frame去获取一个已知资源(在攻击场景中可能是一个点击跟踪脚本或广告服务网络中的资源)。
之后远程服务器会返回某些东西,就像对于这个伪造GET请求的响应,并且这个响应会被很多广泛部署的网络中间设备缓存,从而达到了污染缓存服务器的目的。对于这个攻击的产生的效应,可能一个用户被诱导访问受攻击者操控的服务器,攻击者就有可能污染这个用户以及其他共享相同缓存服务用户的缓存服务器,并跨域执行恶意脚本,破坏web安全模型。
应对措施——掩码
为了避免面这种针对中间设备的攻击,以非HTTP标准的frame作为用户数据的前缀是没有说服力的,因为不太可能彻底发现并检测每个非标准的frame是否能够被非HTTP标准的中间设施识别并略过,也不清楚这些frame数据是否对中间设施的行为产生错误的影响。
对此,WebSocket的防御措施是mask所有从客户端发往服务器的数据,这样恶意脚本(攻击者)就没法获知网络链路上传输的数据是以何种形式呈现的,所以他没法构造可以被中间设施误解为HTTP请求的frame。
这就是掩码存在的原因。
继续安全性探究——如何选择掩码?
本来到这里就该结束了, 但是协议很负责的深入说明了掩码选择上的要求~
客户端必须为发送的每一个frame选择新的掩码,要求是这个掩码无法被提供数据的终端应用(即客户端)预测。
算法的选择上,为了保证随机性,可以借助密码学中的随机数生成器生成每个掩码。
倘若使用相同的掩码会有什么后果呢?
假设每次发送frame使用了相同的掩码或下一个掩码如何选择被猜出的话,攻击者就可以发送经过mask后类似HTTP请求的frame(做法很简单:攻击者以希望在网络链路上显示的形式构造数据,然后用下一个掩码mask再发出去)。
至于如何用掩码mask原始数据,在前面的 学习WebSocket协议—从顶层到底层的实现原理(修订版) 中已经说过了——按位做循环异或运算.
除此之外,另一个要求是一旦传输开始,客户端必须不准再修改传输的内容,否则攻击者将会发送一个用已知数据(如全0)初始化的frame,并通过第一部分数据的回执(经过mask的数据)计算本次使用的掩码,然后修改将要发送的frame使之mask后表现的是一个HTTP请求,原理同前面所讲,不再赘述。
什么数据需要Mask?
上面所描述的安全模型重点关注的是客户端发送类HTTP请求的frame给服务器,所以仅仅需要mask从客户端到服务器的数据,反之则没有mask,但是为了完成请求,前提是客户端必须能够伪造请求。因此,并不强制要求mask双向通信,只要保证一方的数据是经过mask的即可。
遗留问题
尽管掩码提供了保护,但不符合规定的HTTP代理服务器仍是那些“不使用掩码的客户端-服务器”攻击对象!
总结
所有内容归结为一句话:为防止攻击者获知网络链路中传输的原始数据,提供不可预测的掩码至关重要。