Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebSocket协议中Masking Key有什么用? #47

Open
abbshr opened this issue Aug 1, 2015 · 16 comments
Open

WebSocket协议中Masking Key有什么用? #47

abbshr opened this issue Aug 1, 2015 · 16 comments

Comments

@abbshr
Copy link
Owner

abbshr commented Aug 1, 2015

这是机智的面试官问的第三个问题~

我当时回答的比较含糊,因为毕竟一个网络协议的内容如此之复杂,之前也并没有过于关注掩码这东西究竟起什么作用。出于被自己熟悉领域难住的羞愧,面试后立马去翻看RFC,找到好长一大段的描述。

由于目前网络上还没有关于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代理服务器仍是那些“不使用掩码的客户端-服务器”攻击对象!

总结

所有内容归结为一句话:为防止攻击者获知网络链路中传输的原始数据,提供不可预测的掩码至关重要。

@onlyice
Copy link

onlyice commented Nov 9, 2016

兄弟,「针对基础设施的攻击」这段能表述得更详细一点吗?或者给一下你阅读的资料来源?感觉没太理解。。

@abbshr
Copy link
Owner Author

abbshr commented Nov 9, 2016

嗯, 好, 在我看来, 意思就是利用 WebSocket 在 客户端浏览器 构造出 HTTP 请求格式的帧, 因为都是基于 TCP 之上的, 经过缓存服务器时, 这些服务器有可能就把这个帧作为 HTTP 请求来对待, 存在潜在的安全隐患. (mask 这里就是防止你构造出预想的数据格式(HTTP 报文), 以便缓存服务器能够 pass 这些伪造的 HTTP 报文).

原文在这里: https://tools.ietf.org/html/rfc6455#section-10.3
过了好久了, 如果我的解释不合理请一定告诉我, thx~~

@onlyice

@onlyice
Copy link

onlyice commented Nov 9, 2016

感谢答复 😺

那即是说,是因为这些缓存服务器并没有适配 WebSocket 的场景,才导致的问题?如果缓存服务器的实现更科学,是不是就不存在这种情况了?

@fantasycool
Copy link

看下这里的解释,更加方便你们的理解.楼主说的我也没看懂,看了这个明白了

https://security.stackexchange.com/questions/36930/how-does-websocket-frame-masking-protect-against-cache-poisoning

@GalaxyScrew
Copy link

http://www.infoq.com/cn/articles/deep-in-websocket-protocol
这里的是中文的解释,感觉解释的很好

@hhding
Copy link

hhding commented Jun 25, 2019

简单的说吧:

  1. 代理服务器会缓存请求,可以精心发起一个请求,让代理服务器缓存指定的内容,从而使得后续的请求使用被缓存的内容
  2. 通过加入 mask,使得请求不同,从而不会使用有问题的缓存
  3. 其实在 HTTPS 普遍存在的情况下,这个意义不大,因为协商出来的密钥是不一样的,内容就不一样
  4. 一些常见做法譬如请求后面加个随机数或者时间戳也是同样的道理,都是为了避免缓存
  5. 感觉 mask 如果只是为了解决这个问题,其实挺鸡肋的

@youth7
Copy link

youth7 commented Feb 27, 2020

感觉这种污染proxy的行为就算没有websocke和可以进行啊,为何需要专门指出会发生在websocket上呢?
@hhding @abbshr

@yangnianbing
Copy link

感觉这种污染proxy的行为就算没有websocke和可以进行啊,为何需要专门指出会发生在websocket上呢?
@hhding @abbshr

没有websocket,攻击者无法将伪装的响应放到代理服务器上吧

@wathenjiang
Copy link

  • 一些常见做法譬如请求后面加个随机数或者时间戳也是同样的道理,都是为了避免缓存

其实在 HTTPS 普遍存在的情况下,这个意义不大,因为协商出来的密钥是不一样的,内容就不一样 这个说法不太正确吧。即使使用 https 协议,如果不使用 mask-key 还是不能够解决请求被猜到的情况。设计不当的代理服务器在面临相同请求时,就会返回相同的缓存,这与是否使用 https 完全没有关系。

@lsj9383
Copy link

lsj9383 commented Jun 12, 2021

  • 一些常见做法譬如请求后面加个随机数或者时间戳也是同样的道理,都是为了避免缓存

其实在 HTTPS 普遍存在的情况下,这个意义不大,因为协商出来的密钥是不一样的,内容就不一样 这个说法不太正确吧。即使使用 https 协议,如果不使用 mask-key 还是不能够解决请求被猜到的情况。设计不当的代理服务器在面临相同请求时,就会返回相同的缓存,这与是否使用 https 完全没有关系。

我觉得你对这个问题的理解似乎错了。

@hhding
Copy link

hhding commented Jun 15, 2021

  • 一些常见做法譬如请求后面加个随机数或者时间戳也是同样的道理,都是为了避免缓存

其实在 HTTPS 普遍存在的情况下,这个意义不大,因为协商出来的密钥是不一样的,内容就不一样 这个说法不太正确吧。即使使用 https 协议,如果不使用 mask-key 还是不能够解决请求被猜到的情况。设计不当的代理服务器在面临相同请求时,就会返回相同的缓存,这与是否使用 https 完全没有关系。

这么说吧,其实这个涉及到代理本身的工作原理。
在请求 HTTP 的时候,实际上客户端是这么请求的:

  1. TCP socket 连接代理服务器
  2. 往代理服务器发送类似下面内容:
    GET http://www.example.com/ HTTP/1.1
    Proxy-Authorization: Basic encoded-credentials
    Accept: text/html
  3. 服务端返回给你明文请求结果

对于请求 HTTPS 的情况下,一般客户端是这么请求的

  1. TCP socket 连接代理服务器
  2. 往代理服务器发送类似下面内容:
    CONNECT www.example.com:443 HTTP/1.1
    Proxy-Authorization: Basic encoded-credentials
  3. 服务端返回连接成功的消息
  4. 加密啥的客户端直接跟服务端协商

在这种情况下,后续所有传输的信息都是加密信息,每个客户端都是不一样的。也就是说代理服务器看到的内容也是不一样的,即不存在缓存的问题。

另外一种情况是代理服务器直接转发 HTTPS 请求,这种情况我不大确定具体是怎么个协商法,但是确定无疑客户端失去了协商 SSL 协议的能力。只在特殊情况下才适用。

@nobdy
Copy link

nobdy commented Jan 19, 2022

简单的发表一下个人的见解。

  1. 数据为何要进行掩码计算。

    根据 https://datatracker.ietf.org/doc/html/rfc6455#section-10.3 中的说明,虽然客户端发送的请求中是按 Websocket 的规范在应用数据前加上了不符合 HTTP 规范的帧,但是仅仅如此还不够,因为无法排除有些不符合要求的代理服务器可能会跳过此类非 HTTP 的帧,从而不正确的处理此帧的载荷。所以采取的防范措施是将客户端发送给服务器的数据进行掩码处理。因为掩码值是 UA(一般是浏览器)随机生成的,而且每一次客户端执行请求时都会不同,所以攻击者无法得知相应的掩码值,自然就无法构造出在进行掩码处理后的数据是模仿 HTTP 规范的数据。

  2. 现实网络环境是否存在此漏洞。

    从论文《Talking to Yourself for Fun and Profit》中描述的实验步骤可以看出,实验作者在重现此漏洞时在客户端是用 Flash socket 来实现的,并不是用 Websocket 来实现。

    1. Experiment: To evaluate the practicality of mounting IP hijacking and cache poisoning attacks with the WebSocket handshakes, we implemented prototypes for each WebSocket handshake using Flash sockets and a WebSocket server written in Python. We reused the system from the Java and Flash socket experiment with the following changes. We setup a custom multiplexing server at port 80 on the attacking server, which forwards requests to either a standard Apache server or the WebSocket server depending on the request headers. We ran an advertisement campaign for four successive days in November 2010, spending $20 in the Philippines and $80 globally. Our advertisement contains a SWF which performs the WebSocket handshake, spoofs an HTTP request upon handshake success, and instructs the browser to request a script from the target server using a script tag. We experimented with how intermediaries process each WebSocket handshake.

    所以如果实验作者在伪造 HTTP 请求时没有遵守 Websocket 协议(文中似乎并没说明是否如此),那么只是证明原有规范存在安全风险,但并没有完全证实在现实网络环境存在这样可以利用的漏洞。不过即使如此,这也是一个潜在的风险,从协议层面进行预防御是有必要的。

  3. 此设计和 WSS 的关系。

    和 HTTPS 类似,如果 Websocket 数据包在经过代理服务前已经经过加密,即使用 wss,由于内容都是加密过的,代理服务器也无法识别明文,自然无法也不会进行缓存,那么这时无论是否存在掩码的设计,对安全应该都没有什么影响。所以对数据进行掩码计算,主要是为了防范在通讯链路中使用 ws 的节点存在漏洞而设计的。

  4. 安全风险完全杜绝了吗?

    答案是否。如果不采用此设计,有可能攻击者只要发布个钓鱼网站链接,就可以在短时间内展开大范围的攻击。在浏览器对数据载荷进行掩码处理后,就通过加大攻击难度从而极大降低了此漏洞被利用的风险。不过攻击者其实仍有机会进行攻击。

    假设现实网络环境中真的存在这样可以被利用的代理服务器,攻击者可以实现自己的客户端和服务端,然后让自己的客户端通过此代理服务器访问他的服务端,于是成功污染此代理服务器实现攻击目的。不过这样的攻击难度就大大增加了,攻击范围也显著缩小。

@youth7
Copy link

youth7 commented Apr 22, 2022

回来再看还是不太明白,作者提到:

WebSocket的防御措施是mask所有从客户端发往服务器的数据,这样恶意脚本(攻击者)就没法获知网络链路上传输的数据是以何种形式呈现的,所以他没法构造可以被中间设施误解为HTTP请求的frame

不明白为何攻击者就无法获知网络链路上传输的数据了,攻击者只要建立一个钓鱼网站,则他在服务端不是依然可以获取到全部数据吗?

然后还有就是:

为防止攻击者获知网络链路中传输的原始数据,提供不可预测的掩码至关重要。

能举个例子说明一下,如果mask是可预测或者固定的话,攻击者会怎么利用这个来实施攻击?

实施污染攻击的原理是攻击者的服务端返回了一些毒数据,这些非法数据被proxy缓存之后具有毒性。感觉增加mask并不能阻止攻击者的服务端返回毒数据。不知道我哪里理解错了。

@youth7
Copy link

youth7 commented Apr 22, 2022

哦我明白了!

  • 当没有mask,恶意脚本能够轻松伪造一个http请求,然后让浏览器的websocket发送出去毒化proxy。
  • 当有mask,脚本还希望继续伪造http请求的话,则必须知道mask的值,并根据公开的算法去构造数据,以使得被浏览器mask之后发送出去的数据依然是http请求

@newtoncy
Copy link

我还是不明白,攻击者当然知道mask的值,mask是客户端产生的,只要攻击者自己实现一个客户端,就可以构造自己想要的数据在网络上传送了。这时如果服务器返回了类似http响应的帧,缓存就被毒化了。

@chaseSpace
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

13 participants