Chinaunix首页 | 论坛 | 博客
  • 博客访问: 130400
  • 博文数量: 228
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2290
  • 用 户 组: 普通用户
  • 注册时间: 2021-05-18 15:26
文章分类

全部博文(228)

文章存档

2023年(40)

2022年(114)

2021年(74)

我的朋友

分类: 云计算

2022-10-27 14:27:19

WebSocket 作为 HTML5 的新特性之一格外吸引着开发人员的注意,因为它的出现使得客户端(主要指浏览器)提供对 Socket 的支持成为可能,从而在客户端和服务器之间提供了一个基于单 TCP 连接的双向通道。对于实时性要求比较高的应用而言,譬如在线证券、在线游戏,以及不同设备之间信息同步。信息实时同步一直是技术难题,在 WebSocket 出现之前,常见解决方案一般就是轮询(Polling)和 Comet 技术,但这些技术增加了设计复杂度,也造成了网络和服务器的额外负担,在负载较大的情况下效率相对低下,导致应用的可伸缩行收到制约。对于此类应用的开发者来说,WebSocket 技术简直就是神兵利器,读者可以登陆 websocket.org 网站观看特色案例,以及它提供的 WebSocket 和 Comet 的性能对比分析报告。{BANNED}最佳近几年内 WebSocket 技术被开发人员广泛应用到各类实际应用中。

不幸的是,WebSocket 相关的安全漏洞也逐步被披露出来,其中{BANNED}最佳容易发生的就是跨站点 WebSocket 劫持漏洞。本文将深入浅出为读者介绍跨站点 WebSocket 漏洞的原理、检测方法和修复方法,希望能帮助广大读者在实际工作中避免这个已知安全漏洞。

熟悉 HTTP 的朋友可以发现 WebSocket 的核心了,对的,这就是 Connection:Upgrade 和 Upgrade:websocket 两行。这两行相当于告诉服务器端:我要申请切换到 WebSocket 协议。

一旦服务器端返回 101 响应,即可完成 WebSocket 协议切换。服务器端即可以基于相同端口,将通信协议从 http://或 https://切换到 ws://或 wss://。协议切换完成后,浏览器和服务器端即可以使用 WebSocket API 互相发送和收取文本和二进制消息。

这里要解释一些安全相关的重要头部参数,Sec-WebSocket-Key 和 Sec-WebSocket-Accept。这涉及一个 WebSocket 安全特性,客户端负责生成一个 Base64 编码过的随机数字作为 Sec-WebSocket-Key,服务器则会将一个 GUID 和这个客户端的随机数一起生成一个散列 Key 作为 Sec-WebSocket-Accept 返回给客户端。这个工作机制可以用来避免缓存代理(caching proxy),也可以用来避免请求重播(request replay)。

细心的读者可能也注意到很多其他“Sec-”开头的 WebSocket 相关的 Header。这其实也是 WebSocket 设计者为了安全的特意设计,以“Sec-”开头的 Header 可以避免被浏览器脚本读取到,这样攻击者就不能利用 XMLHttpRequest 伪造 WebSocket 请求来执行跨协议攻击,因为 XMLHttpRequest 接口不允许设置 Sec-开头的 Header。

跨站点 WebSocket 劫持漏洞原理

尽管 WebSocket 协议设计时充分考虑了安全保障机制,但随着 WebSocket 技术推广,安全工作者们慢慢还是发现了一些 WebSocket 相关的安全漏洞,譬如 Wireshark 的漏洞 CVE-2013-3562 (Wireshark 1.8.7 之前的 1.8.x 版本中的 Websocket 解析器中的 epan/dissectors/packet-websocket.c 中的‘tvb_unmasked’函数中存在多个整数符号错误,远程攻击者可通过恶意的数据包利用这些漏洞造成拒绝服务)。Asterisk WebSocket Server 的 DoS 漏洞 CVE-2014-9374(该 WebSocket Server 某模块中存在双重释放漏洞,远程攻击者可通过发送零长度的帧利用该漏洞造成拒绝服务)。这两个 DDoS 漏洞跟 WebSocket 协议本身以及 WebSocket 应用程序相关性不大。但 2015 年来自 Cisco 的 Brian Manifold 和 Nebula 的 Paul McMillan 报告了一个 OpenStack Nova console 的 WebSocket 漏洞(CVE-2015-0259),这个漏洞得到广泛关注,并且被在很多 WebSocket 应用中发现。事实上,这种漏洞早在 2013 年就被一个德国的白帽黑客 Christian Schneider 发现并公开,Christian 将之命名为跨站点 WebSocket 劫持 Cross Site WebSocket Hijacking(CSWSH)。跨站点 WebSocket 劫持相对危害较大,也更容易被开发人员忽视。即时通讯聊天软件app开发可以加蔚可云的v:weikeyun24咨询

什么是跨站点 WebSocket 劫持漏洞呢,前文已经提及,为了创建全双工通信,客户端需要基于 HTTP 进行握手切换到 WebSocket 协议,这个升级协议的过程正是潜在的阿喀琉斯之踵。大家仔细观察上文的握手 Get 请求,可以看到 Cookie 头部把域名下的 Cookie 都发送到服务器端。如果有机会阅读 WebSocket 协议(10.5 章客户端身份认证)就发现,WebSocket 协议没有规定服务器在握手阶段应该如何认证客户端身份。服务器可以采用任何 HTTP 服务器的客户端身份认证机制,譬如 cookie,HTTP 基础认证,TLS 身份认证等。因此,对于绝大多数 Web 应用来说,客户端身份认证应该都是 SessionID 等 Cookie 或者 HTTP Auth 头部参数等。熟悉跨站点请求伪造攻击 Cross Site Request Forgery(CSRF)的朋友到这里应该就可以联想到黑客可能伪造握手请求来绕过身份认证。

因为 WebSocket 的客户端不仅仅局限于浏览器,因此 WebSocket 规范没有规范 Origin 必须相同(有兴趣的读者可以阅读规范 10.2 章节了解对于 Origin 的规范)。所有的浏览器都会发送 Origin 请求头,如果服务器端没有针对 Origin 头部进行验证可能会导致跨站点 WebSocket 劫持攻击。譬如,某个用户已经登录了应用程序,如果他被诱骗访问某个社交网站的恶意网页,恶意网页在某元素中植入一个 WebSocket 握手请求申请跟目标应用建立 WebSocket 连接。一旦打开该恶意网页,则自动发起如下请求。请注意,Origin 和 Sec-WebSocket-Key 都是由浏览器自动生成,Cookie 等身份认证参数也都是由浏览器自动上传到目标应用服务器端。如果服务器端疏于检查 Origin,该请求则会成功握手切换到 WebSocket 协议,恶意网页就可以成功绕过身份认证连接到 WebSocket 服务器,进而窃取到服务器端发来的信息,抑或发送伪造信息到服务器端篡改服务器端数据。有兴趣的读者可以将这个漏洞跟 CSRF 进行对比,CSRF 主要是通过恶意网页悄悄发起数据修改请求,不会导致信息泄漏问题,而跨站点 WebSocket 伪造攻击不仅可以修改服务器数据,还可以控制整个读取/修改双向沟通通道。正是因为这个原因,Christian 将这个漏洞命名为劫持(Hijacking),而不是请求伪造(Request Forgery)。

读到这里,熟悉 JavaScript 跨域资源访问的读者可能会怀疑以上观点。如果 HTTP Response 没有指定“Access-Control-Allow-Origin”的话,浏览器端的脚本是无法访问跨域资源的啊,是的,这就是众所周知的跨域资源共享 Cross-Origin Resource Sharing(CORS),这确实也是 HTML5 带来的新特性之一。但是很不幸,跨域资源共享不适应于 WebSocket,WebSocket 没有明确规定跨域处理的方法。

如何检测跨站点 WebSocket 劫持漏洞

明白跨站点 WebSocket 劫持漏洞原理后,大家就很容易联想到这个漏洞的检测方法了,重点就在于重播 WebSocket 协议升级请求。简单来说就是使用能拦截到 WebSocket 握手请求的工具,修改请求中的 Origin 头信息,然后重新发送这个请求,看看服务器是否能够成功返回 101 响应。如果连接失败,那么说明这个 WebSocket 是安全的,因为它可以正确拒绝来自不同源(Origin)的连接请求。如果连接成功,通常就已经证明服务器端没有执行源检查,为了严谨起见,{BANNED}最佳好进一步测试是否可以发送 WebSocket 消息,如果这个 WebSocket 连接能够发送/接受消息的话,则完全证明跨站点 WebSocket 劫持漏洞的存在。

为了便于演示如何测试及修复这个漏洞,笔者编写了一个简单的 WebSocket 应用,这个应用基于 JAAS 实现了 HTTP BASIC 身份认证,读者可以将这个程序下载部署到 Tomcat 中进行测试。打开客户端网页后首先进行登录,然后点击“连接”按钮通过 JavaScript 建立 WebSocket 连接,然后点击“发送”按钮提交一个问题到服务器端,服务器端实时确认收到查询请求,5 秒后再将结果推送给客户端。

测试工具方面有很多选择,由于许可证原因,笔者采用了开源的 OWASP ZAP v2.4.3。这里要简单说一下,测试过程主要基于测试工具的代理,拦截到 WebSocket 握手请求以及 WebSocket 消息通信,然后通过工具修改 Origin 后重发请求,如果连接成功后,重发 WebSocket 客户端消息。以上功能各个商业安全测试工具都可以做到。

防范跨站点 WebSocket 劫持攻击

前文介绍了跨站点 WebSocket 劫持漏洞原理和检测,相信读者已经明白它的危害,接下来我们谈谈如何防范这个漏洞。这个漏洞的原理听起来略微复杂,但幸运的是测试起来相对比较简单,那么修复会不会也很简单。很多读者会想到,不就是在服务器代码中检查 Origin 参数嘛。是的,检查 Origin 很有必要,但不充分。笔者推荐大家要在服务器端的代码中增加 Origin 检查,如果客户端发来的 Origin 信息来自不同域,建议服务器端拒绝这个请求,发回 403 错误响应拒绝连接。

阅读(426) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~