Web网络传输协议层安全:websocket安全分析

2023年 7月 10日 56.2k 0

一.概述

WebSocket 是HTML5一种新的网络传输协议,位于 OSI 模型的应用层,可在单个TCP连接上进行全双工通信。

1.1HTTP 和 WebScoket

段落的首行要缩进,表格居中放置,如表1。 字体通一用一种雅黑或宋体,文字字号统一为5号Web 客户端和服务端之间的大多数通信使用HTTP(HTTPS也是在传输层和应用层中间加了一层SSL/TLS协议,在这里没有太大影响,故不作区分)。HTTP协议是请求-响应式的,在 HTTP1.1 开始,TCP连接可被复用。即使网络连接保持打开状态,这也将用于请求和响应的单独事务。

WebSocket和HTTP都是应用层协议,并且都基于TCP协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以建立持久性的连接,并进行双向数据传输。此外,WebSocket基于二进制帧进行传输。

RFC 6455中规定:

WebSocket通过HTTP端口80和443进行工作,并支持HTTP代理和中介,从而使其与HTTP协议兼容。

TIPS:ws协议默认80端口,wss默认443端口

为了实现兼容性,WebSocket握手使用HTTP Upgrade 头从HTTP协议更改为WebSocket协议。与HTTP协议类似, `wss` 协议建立在一个加密的TLS连接的WebSocket,而 `ws` 协议使用未加密的连接。

1.2Demo

  • 安装依赖

npm install ws

  • server.js

// 导入WebSocket模块: const WebSocket = require('ws'); ​ // 引用Server类: const WebSocketServer = WebSocket.Server; ​ // 实例化: const ws = new WebSocketServer({ port: 3000 }); ​ // connection事件用于处理接入的WebSocket ws.on('connection', function (ws) { console.log("Connected!!!"); });

node tt.js 启动服务端

  • client

直接在浏览器的console界面输入,在服务端的终端会打印相关的日志信息

var ws = new WebSocket("ws://127.0.0.1:3000");

1.3握手过程

服务端:

var ws = new WebSocket("ws://127.0.0.1:3000"); Loaded!!

客户端发起握手请求

GET / HTTP/1.1 Host: 127.0.0.1:3000 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0 Accept: */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Sec-WebSocket-Version: 13 Origin: http://127.0.0.1 Sec-WebSocket-Key: 8PbhQOV5ykV3eYf2biw52A== Connection: keep-alive, Upgrade Sec-Fetch-Dest: websocket Sec-Fetch-Mode: websocket Sec-Fetch-Site: same-site Pragma: no-cache Cache-Control: no-cache Upgrade: websocket ​ ​如果服务端接受这个连接,它会返回一个WebSocket回复

HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: dBaGq6Oh1nXvQd+sJRKFK9GnsGI=

之后,这个WebSocket的网络连接会保持开启状态,任意一方都可以直接发送WebSocket信息:

var ws = new WebSocket("ws://127.0.0.1:3000"); ​ // 连接打开事件 ws.onopen = function() { // 发送数据给服务端 ws.send(JSON.stringify({"message":"hello"})); }; ​ // 监听服务端信息 ws.onmessage = function(e){ alert(e.data); }; Loaded!! ​

通过 message 监听消息

// 导入WebSocket模块: const WebSocket = require('ws'); ​ // 引用Server类: const WebSocketServer = WebSocket.Server; ​ // 实例化: const ws = new WebSocketServer({ port: 3000 }); ​ // connection事件用于处理接入的WebSocket ws.on('connection', function (ws) { // 处理客户端的消息 ws.on('message', function (data) { console.log(JSON.parse(data)); }); ​ // 向客户端发送消息 ws.send("OK"); ​ });

原则上,WebSocket消息可以包含任何内容或数据格式。在实际的应用程序中,通常WebSocket消息都是通过JSON进行发送结构化数据。

关于WebSocket握手时的一些特性:

  • Connection和Upgrade头部用来标识这是一个WebSocket握手消息。
  • Sec-WebSocket-Version请求头明确了一个客户端希望使用的WebSocket协议版本。版本13最常用。
  • Sec-WebSocket-Key请求头包含了一个base64编码的随机值,在每个WebSocket握手请求中,它一定是随机生成的。
  • Sec-WebSocket-Accept响应头的值是客户端发送的握手请求中Sec-WebSocket-key的哈希值,并与协议规范中定义的特定字符串连接。这样做的目的是匹配每一对握手请求,防止由于错误的配置或者缓存代理导致的连接错误。

1.4握手过程

基于WebSocket全双工、延迟的特性,应用场景比较广泛。

  • 聊天机器人
  • 弹幕
  • 协同编辑
  • 股票报价实施更新
  • 位置更新
  • 直播实况段落的首行要

二. 安全分析

根据上面的分析可知,WebSocket仅仅是Web程序中的一种通信协议,并不会解决Web应用中存在的安全问题。因此,原则上任何Web漏洞都有可能出现在使用WebSocket的应用中。

2.1Web漏洞

WebSocket中,用户可控的请求数据,都会涉及输入校验问题,用来规范常见的Web漏洞,如XSS、SQL Inject、RCE等。

2.1.1XSS

靶场环境:https://acb51fa71e7c52cbc04a0bac00b7009c.web-security-academy.net/

题目环境是一个商城,其中有个在线聊天功能,是基于WebSocket

to server

{"message":""}

to client

{"user":"You","content":""}

页面渲染后触发js

Web网络传输协议层安全:websocket安全分析

TIPS:新版的Burp 支持WebSocket包重放

2.2 WebSocket 安全

2.2.1认证

WebSocket 协议并没有在握手阶段对客户端的身份进行认证,但服务端可以采用HTTP服务器的客户端身份认证机制,如cookie认证,HTTP 基础认证,TLS 身份认证等。因此,认证实现方面的安全问题与基于HTTP的Web认证并无区别。

  • CVE-2015-0201

Spring框架的Java SockJS客户端生成可预测的会话ID,攻击者可利用该漏洞向其他会话发送消息

  • CVE-2015-1482

Ansible Tower未对用户身份进行认证,远程攻击者通过websocket连接获取敏感信息

2.2.2授权

WebSocket 协议依然没有指定任何授权方式,因此关于权限的相关策略依然得依赖开发者在服务端实现,依然面临着垂直权限提升和水平权限提升的风险。

2.2.3跨域请求/CSWSH

WebSocket使用基于源的安全模型,在发起WebSocket握手请求时,浏览器会在请求中添加一个名为Origin的HTTP头,Oringin字段表示发起请求的源,以此来防止未经授权的跨站点访问请求。

WebSocket 的客户端不仅仅局限于浏览器,因此 WebSocket 规范没有强制规定握手阶段的 Origin 头是必需的,并且WebSocket不受浏览器同源策略、CORS机制的限制。如果服务端没有针对Origin头部进行验证可能会导致跨站点WebSocket劫持攻击。

CSWSH全称Cross-site WebSocket Hijacking,跨站点WebSocket劫持漏洞。

该漏洞最早在 2013 年被Christian Schneider 发现并公开,Christian 将之命名为跨站点 WebSocket 劫持 (Cross Site WebSocket Hijacking)(CSWSH)。跨站点 WebSocket 劫持危害大,但容易被开发人员忽视。相关案例可以参考: IPython Notebook(CVE-2014-3429), OpenStack Compute(CVE-2015-0259), Zeppelin WebSocket服务器等跨站WebSocket劫持。

攻击过程:

Web网络传输协议层安全:websocket安全分析

需要注意的是,Origin 和 Sec-WebSocket-Key 都是由浏览器自动生成的,浏览器再次发起请求访问目标服务器会自动带上Cookie 等身份认证参数。

漏洞利用的关键点是,服务端没有对Origin头部进行校验,才能成功握手并切换到 WebSocket 协议,恶意网页就可以成功绕过身份认证连接到 WebSocket 服务器,进而窃取到服务器端发来的信息,或者发送伪造信息到服务器端篡改服务器端数据。

检测

由于跨站点WebSocket劫持攻击本质上是WebSocket握手上的CSRF漏洞,因此,首先需要确认在WebSocket握手过程中,是否进行了CSRF防护,确定是否仅仅依赖HTTP cookie进行权限鉴定。

HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Cookie: session=KOsEJNuflw4Rxxxxxxxxxxxxxx Sec-WebSocket-Accept: dBaGq6Oh1nXvQd+sJRKFK9GnsGI=

TIPS:Sec-WebSocket-Key头包含一个随机值,以防止缓存代理的错误,而不是用于身份验证或会话处理的目的。

在确定握手请求存在CSRF风险的情况下,寻找使用WebSocket进行敏感数据检索的功能点。

过程:

  • 重放确认是否存在CSRF
  • 修改Origin头部,判断是否存在校验
  • 对比CSRF

    与传统跨站请求伪造(CSRF)攻击相比,CSRF 主要是通过恶意网页悄悄发起数据修改请求,而跨站 WebSocket 伪造攻击不仅可以修改服务器数据,还可以控制整个双向通信通道。也正是因为这个原因,Christian 将这个漏洞命名为劫持(Hijacking),而不是请求伪造(Request Forgery)。

    防御
    • 检查客户端请求中的Origin信息是否跨域
    • 防止Origin头部伪造,还可以借鉴CSRF的防御机制,如增加Token验证

    2.2.4 拒绝服务攻击/DOS

    WebSocket设计为面向连接的协议,如果不限制连接数,可能会导致DoS风险。

    F5 BIG-IP远程拒绝服务漏洞(CVE-2016-9253)

    • 客户端拒绝服务

    WebSocket 连接限制不同于HTTP连接限制,WebSocket有一个更高的连接限制,不同的浏览器的最大连接数也存在差异。如:火狐浏览器默认最大连接数为200。

    通过发送恶意内容,占用所有Websocket,导致浏览器资源耗尽,引起拒绝服务。

    • 服务端拒绝服务
      • 发起大量连接

    WebSocket建立的是持久连接,只有客户端或服务端其中一方发起关闭连接的请求,连接才会关闭。攻击者可以通过发起请求并建立大量的连接,导致服务器资源耗尽,引发拒绝服务攻击。

    防御:服务端可以进行单一IP的最大连接数进行防御

    • 大数据帧占用

    攻击者可以发送一个庞大的数据帧,占用服务端的内存,引发拒绝服务攻击,

    防御:限制帧的大小

    demo
    • js

    var WebSocketServer = require('ws').Server, wss = new WebSocketServer({ port: 3000 }); wss.on('connection', function (ws) { console.log('[*]Client connected!'); ws.on('message', function (message) { console.log(message.toString('utf8')); }); });

    • 正常客户端

    var ws = new WebSocket("ws://127.0.0.1:3000"); ​ // 连接打开事件 ws.onopen = function() { // 发送数据给服务端 ws.send("Hello"); }; ​ // 监听服务端信息 ws.onmessage = function(e){ alert(e.data); }; Loaded!!

    • exp

    python -m pip install ws4py from ws4py.client.threadedclient import WebSocketClient ​ ​ class WS_Client(WebSocketClient): ​ # 需要重写以下三个方法 def opened(self): reqData = "Hello" self.send(reqData)

    def closed(self, code, reason=None): print("[-] Closed down:", code, reason)

    def received_message(self, resp): resp = json.loads(str(resp)) print(resp) ​ ​ if __name__ == '__main__': while True: ws = WS_Client("ws://127.0.0.1:3000") ws.connect()

    2.2.5 中间人攻击

    WebSocket使用HTTP或HTTPS协议进行握手请求,在使用HTTP协议的情况下,若存在中间人可以嗅探HTTP流量,那么中间人可以获取并篡改WebSocket握手请求,通过伪造客户端信息与服务器建立WebSocket连接。短文章可以不引用目录

    三.总结

    WebSocket 是HTML5中一个及时的全双工通讯协议,在性能上有着明显的优势,但他并不能解决安全问题,同时也需要开发者考虑其安全威胁面。

    四.参考

    https://christian-schneider.net/CrossSiteWebSocketHijacking.html

    https://www.liaoxuefeng.com/wiki/1022910821149312/1103327377678688

    https://segmentfault.com/q/1010000020661067

    https://www.mi1k7ea.com/2019/10/04/CSWSH%E6%BC%8F%E6%B4%9E%E6%80%BB%E7%BB%93/#0x02-CSWSH%E6%BC%8F%E6%B4%9E

    https://security.tencent.com/index.php/blog/msg/119

    https://www.mi1k7ea.com/2021/01/30/%E6%B5%85%E6%9E%90WebSocket%E5%AE%89%E5%85%A8/

    https://www.freebuf.com/articles/web/252298.html

    https://wiki.wgpsec.org/knowledge/web/websocket-sec.html

    https://www.mi1k7ea.com/2021/01/30/%E6%B5%85%E6%9E%90WebSocket%E5%AE%89%E5%85%A8/

    相关文章

    Mallox勒索软件新Linux变种现世
    伪装成破解程序和商业工具的新型恶意软件正在传播
    Orcinius后门新样本分析
    Poseidon窃取程序通过Google广告感染Mac用户
    大选开始之际,欧盟各政党遭受 DDoS 攻击
    微软2024

    发布评论