exploiting-excessive-data-exposure-in-api

测试 API 是否存在过度数据暴露,即端点返回的数据超出客户端应用程序实际需要的量,依赖前端过滤敏感字段。测试人员拦截 API 响应并分析其中泄露的 PII、内部标识符、调试信息或 UI 不显示但 API 传输的敏感业务数据。对应 OWASP API3:2023 对象属性级授权破坏。适用于 API 数据泄露测试、过度数据暴露、响应过滤绕过或 API 过度获取等请求场景。

9 stars

Best use case

exploiting-excessive-data-exposure-in-api is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

测试 API 是否存在过度数据暴露,即端点返回的数据超出客户端应用程序实际需要的量,依赖前端过滤敏感字段。测试人员拦截 API 响应并分析其中泄露的 PII、内部标识符、调试信息或 UI 不显示但 API 传输的敏感业务数据。对应 OWASP API3:2023 对象属性级授权破坏。适用于 API 数据泄露测试、过度数据暴露、响应过滤绕过或 API 过度获取等请求场景。

Teams using exploiting-excessive-data-exposure-in-api 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/exploiting-excessive-data-exposure-in-api/SKILL.md --create-dirs "https://raw.githubusercontent.com/killvxk/cybersecurity-skills-zh/main/skills/exploiting-excessive-data-exposure-in-api/SKILL.md"

Manual Installation

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

How exploiting-excessive-data-exposure-in-api Compares

Feature / Agentexploiting-excessive-data-exposure-in-apiStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

测试 API 是否存在过度数据暴露,即端点返回的数据超出客户端应用程序实际需要的量,依赖前端过滤敏感字段。测试人员拦截 API 响应并分析其中泄露的 PII、内部标识符、调试信息或 UI 不显示但 API 传输的敏感业务数据。对应 OWASP API3:2023 对象属性级授权破坏。适用于 API 数据泄露测试、过度数据暴露、响应过滤绕过或 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

# 利用 API 中的过度数据暴露漏洞

## 适用场景

- 测试前端显示数据子集但 API 响应包含额外字段的 API
- 评估移动应用程序 API,这些 API 的响应是为多种客户端类型设计的,可能包含多余数据
- 识别 API 响应中泄露的 PII,包括 UI 未显示的电子邮件地址、电话号码、社会安全号码或支付数据
- 测试 GraphQL API,客户端可以请求包括敏感属性在内的任意字段
- 评估微服务重构后,内部服务间数据是否泄露到公共端点

**不适用于**:未获得书面授权的情况。数据暴露测试涉及捕获和分析潜在的敏感个人数据。

## 前置条件

- 书面授权,注明目标 API 端点和范围
- Burp Suite Professional 或 mitmproxy 配置为拦截代理
- 两个不同权限级别的测试账户(普通用户和管理员)
- 浏览器开发者工具或移动端代理设置,用于流量捕获
- Python 3.10+,安装 `requests` 和 `json` 库
- API 文档(OpenAPI 规范),用于与实际响应进行比较

## 工作流程

### 步骤 1:响应 Schema 发现

将文档化的 API 响应与实际响应进行比较:

```python
import requests
import json

BASE_URL = "https://target-api.example.com/api/v1"
headers = {"Authorization": "Bearer <user_token>", "Content-Type": "application/json"}

# 获取资源并分析所有返回字段
endpoints_to_test = [
    ("GET", "/users/me", None),
    ("GET", "/users/me/orders", None),
    ("GET", "/products", None),
    ("GET", "/users/me/settings", None),
    ("GET", "/transactions", None),
]

for method, path, body in endpoints_to_test:
    resp = requests.request(method, f"{BASE_URL}{path}", headers=headers, json=body)
    if resp.status_code == 200:
        data = resp.json()
        # 递归提取所有字段名
        def extract_fields(obj, prefix=""):
            fields = []
            if isinstance(obj, dict):
                for k, v in obj.items():
                    full_key = f"{prefix}.{k}" if prefix else k
                    fields.append(full_key)
                    fields.extend(extract_fields(v, full_key))
            elif isinstance(obj, list) and obj:
                fields.extend(extract_fields(obj[0], f"{prefix}[]"))
            return fields

        all_fields = extract_fields(data)
        print(f"\n{method} {path} - 返回了 {len(all_fields)} 个字段:")
        for f in sorted(all_fields):
            print(f"  {f}")
```

### 步骤 2:敏感数据模式检测

扫描 API 响应中的敏感数据模式:

```python
import re

SENSITIVE_PATTERNS = {
    "email": r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
    "phone": r'(\+?1?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4})',
    "ssn": r'\b\d{3}-\d{2}-\d{4}\b',
    "credit_card": r'\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13})\b',
    "password_hash": r'\$2[aby]?\$\d{2}\$[./A-Za-z0-9]{53}',
    "api_key": r'(?:api[_-]?key|apikey)["\s:=]+["\']?([a-zA-Z0-9_\-]{20,})',
    "internal_ip": r'\b(?:10\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])|192\.168)\.\d{1,3}\.\d{1,3}\b',
    "aws_key": r'AKIA[0-9A-Z]{16}',
    "jwt_token": r'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+',
    "uuid": r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}',
}

SENSITIVE_FIELD_NAMES = [
    "password", "password_hash", "secret", "token", "ssn", "social_security",
    "credit_card", "card_number", "cvv", "pin", "private_key", "api_key",
    "internal_id", "debug", "trace", "stack_trace", "created_by_ip",
    "last_login_ip", "salt", "session_id", "refresh_token", "mfa_secret",
    "date_of_birth", "bank_account", "routing_number", "tax_id"
]

def scan_response(endpoint, response_text):
    findings = []
    # 检查值中的敏感数据模式
    for pattern_name, pattern in SENSITIVE_PATTERNS.items():
        matches = re.findall(pattern, response_text)
        if matches:
            findings.append({
                "endpoint": endpoint,
                "type": "sensitive_value",
                "pattern": pattern_name,
                "count": len(matches),
                "sample": matches[0][:20] + "..." if len(matches[0]) > 20 else matches[0]
            })

    # 检查敏感字段名
    response_lower = response_text.lower()
    for field in SENSITIVE_FIELD_NAMES:
        if f'"{field}"' in response_lower or f"'{field}'" in response_lower:
            findings.append({
                "endpoint": endpoint,
                "type": "sensitive_field",
                "field_name": field
            })

    return findings

# 扫描所有端点响应
for method, path, body in endpoints_to_test:
    resp = requests.request(method, f"{BASE_URL}{path}", headers=headers, json=body)
    if resp.status_code == 200:
        findings = scan_response(f"{method} {path}", resp.text)
        for f in findings:
            print(f"[发现] {f['endpoint']}: {f['type']} - {f.get('pattern', f.get('field_name'))}")
```

### 步骤 3:比较 UI 显示字段与 API 响应字段

```python
# UI 显示的字段(从前端应用程序观察到的)
ui_displayed_fields = {
    "/users/me": {"name", "email", "avatar_url", "role"},
    "/users/me/orders": {"order_id", "date", "status", "total"},
    "/products": {"id", "name", "price", "image_url", "description"},
}

# API 实际返回的字段
for method, path, body in endpoints_to_test:
    resp = requests.request(method, f"{BASE_URL}{path}", headers=headers, json=body)
    if resp.status_code == 200:
        data = resp.json()
        if isinstance(data, list):
            actual_fields = set(data[0].keys()) if data else set()
        elif isinstance(data, dict):
            # 处理分页响应
            items_key = next((k for k in data if isinstance(data[k], list)), None)
            if items_key and data[items_key]:
                actual_fields = set(data[items_key][0].keys())
            else:
                actual_fields = set(data.keys())
        else:
            continue

        expected = ui_displayed_fields.get(path, set())
        excess = actual_fields - expected
        if excess:
            print(f"\n{method} {path} - 多余字段(UI 未显示):")
            for field in sorted(excess):
                print(f"  - {field}")
```

### 步骤 4:测试相关端点中的用户对象暴露

```python
# 许多 API 在订单、评论等响应中嵌入完整的用户对象
endpoints_with_user_objects = [
    "/orders",          # 每个订单可能包含完整的卖方/买方个人资料
    "/comments",        # 评论可能包含完整的作者个人资料
    "/reviews",         # 评价可能暴露评价者详情
    "/transactions",    # 交易可能包含对方信息
    "/team/members",    # 团队列表可能暴露过多成员数据
]

for path in endpoints_with_user_objects:
    resp = requests.get(f"{BASE_URL}{path}", headers=headers)
    if resp.status_code == 200:
        text = resp.text
        # 检查嵌套对象中的用户数据泄露
        user_fields_found = []
        for field in ["password_hash", "last_login_ip", "mfa_enabled", "phone_number",
                      "date_of_birth", "ssn", "internal_notes", "salary", "address"]:
            if f'"{field}"' in text:
                user_fields_found.append(field)
        if user_fields_found:
            print(f"[过度暴露] {path} 暴露了用户字段:{user_fields_found}")
```

### 步骤 5:GraphQL 过度获取分析

```python
# GraphQL 允许客户端请求任何可用字段
GRAPHQL_URL = f"{BASE_URL}/graphql"

# 内省查询以发现 User 类型上的所有字段
introspection = {
    "query": """
    {
      __type(name: "User") {
        fields {
          name
          type {
            name
            kind
          }
        }
      }
    }
    """
}

resp = requests.post(GRAPHQL_URL, headers=headers, json=introspection)
if resp.status_code == 200:
    fields = resp.json().get("data", {}).get("__type", {}).get("fields", [])
    print("通过 GraphQL 可用的 User 字段:")
    for f in fields:
        sensitivity = "敏感" if f["name"] in SENSITIVE_FIELD_NAMES else "普通"
        print(f"  {f['name']} ({f['type']['name']}) [{sensitivity}]")

# 尝试查询敏感字段
sensitive_query = {
    "query": """
    query {
      users {
        id
        email
        passwordHash
        socialSecurityNumber
        internalNotes
        lastLoginIp
        mfaSecret
        apiKey
      }
    }
    """
}
resp = requests.post(GRAPHQL_URL, headers=headers, json=sensitive_query)
if resp.status_code == 200 and "errors" not in resp.json():
    print("[严重] GraphQL 无限制地暴露了敏感用户字段")
```

### 步骤 6:调试和内部数据泄露

```python
# 测试响应中的调试信息
debug_headers_to_check = [
    "X-Debug-Token", "X-Debug-Info", "Server", "X-Powered-By",
    "X-Request-Id", "X-Correlation-Id", "X-Backend-Server",
    "X-Runtime", "X-Version", "X-Build-Version"
]

resp = requests.get(f"{BASE_URL}/users/me", headers=headers)
for h in debug_headers_to_check:
    if h.lower() in {k.lower(): v for k, v in resp.headers.items()}:
        print(f"[信息泄露] 响应头 {h}: {resp.headers.get(h)}")

# 测试错误响应中是否包含堆栈跟踪
error_payloads = [
    ("GET", "/users/invalid-id-format", None),
    ("POST", "/orders", {"invalid": "payload"}),
    ("GET", "/users/-1", None),
    ("GET", "/users/0", None),
]

for method, path, body in error_payloads:
    resp = requests.request(method, f"{BASE_URL}{path}", headers=headers, json=body)
    if resp.status_code >= 400:
        text = resp.text.lower()
        if any(kw in text for kw in ["stack trace", "traceback", "at com.", "at org.",
                                      "file \"", "line ", "exception", "sql", "query"]):
            print(f"[调试泄露] {method} {path} -> {resp.status_code}: 包含堆栈跟踪或查询信息")
```

## 核心概念

| 术语 | 定义 |
|------|------|
| **过度数据暴露(Excessive Data Exposure)** | API 返回的数据字段超出客户端需要的量,依赖前端过滤向用户隐藏敏感信息 |
| **过度获取(Over-Fetching)** | 请求或接收超出特定操作所需的数据量,在返回固定响应 Schema 的 REST API 中很常见 |
| **响应过滤(Response Filtering)** | 客户端过滤 API 响应数据以只显示相关字段,由于完整响应可被拦截,这不提供任何安全保障 |
| **对象属性级授权(Object Property Level Authorization)** | OWASP API3:2023 - 确保用户只能读取/写入他们被授权访问的对象属性 |
| **PII 泄露(PII Leakage)** | API 响应中意外暴露个人身份信息,包括姓名、邮件地址、地址、社会安全号码或财务数据 |
| **Schema 验证(Schema Validation)** | 强制 API 响应符合定义的 Schema,在传输前去除未授权字段 |

## 工具与系统

- **Burp Suite Professional**:拦截 API 响应并使用 Comparer 工具对比预期与实际响应 Schema
- **mitmproxy**:可编写脚本的代理,支持基于 Python 的内容检测脚本进行自动化响应分析
- **OWASP ZAP**:被动扫描器,自动检测请求头、错误消息和响应体中的信息披露
- **Postman**:使用测试脚本比较文档化的响应 Schema 与实际 API 响应
- **jq**:命令行 JSON 处理器,用于从 API 响应中提取和分析特定字段

## 常见场景

### 场景:移动银行 API 数据暴露评估

**场景背景**:某移动银行应用程序的 API 向移动客户端返回完整的账户对象,而应用只显示账户昵称和余额。该 API 同时被 iOS 和 Android 应用以及 Web 门户访问。

**方法**:
1. 在测试设备上配置 mitmproxy,以测试用户身份进行认证
2. 在完整用户会话期间(登录、查看账户、转账、登出)捕获所有 API 响应
3. 分析 `GET /api/v1/accounts` 响应:UI 显示 4 个字段,但 API 返回 23 个字段
4. 发现 API 返回 `routing_number`、`account_holder_ssn_last4`、`internal_risk_score`、`kyc_verification_status` 和 `linked_external_accounts` - UI 均未显示
5. 分析 `GET /api/v1/transactions` 响应:API 返回客户端不需要的 `merchant_id`、`terminal_id`、`authorization_code`、`processor_response` 字段
6. 检查 `GET /api/v1/users/me`:API 返回 `last_login_ip`、`mfa_backup_codes_remaining`、`account_officer_name` 和 `credit_score_band`
7. 测试错误响应:向 `POST /api/v1/transfers` 发送无效载荷,错误消息中返回 SQL 表名

**常见陷阱**:
- 只检查顶级字段,遗漏深层嵌套对象中的敏感数据
- 不测试分页响应,后续页面可能包含不同的字段
- 忽视可能泄露服务器版本、后端技术或内部路由信息的响应头
- 忽略错误响应中的数据暴露,这些响应通常包含堆栈跟踪、SQL 查询或内部路径
- 假设 HTTPS 加密能防止数据暴露(HTTPS 保护传输中的数据,但不能防止已认证客户端访问)

## 输出格式

```
## 发现:账户和交易 API 中存在过度数据暴露

**ID**: API-DATA-001
**严重性**: 高(CVSS 7.1)
**OWASP API**: API3:2023 - 对象属性级授权破坏
**受影响端点**:
  - GET /api/v1/accounts
  - GET /api/v1/transactions
  - GET /api/v1/users/me

**描述**:
API 向客户端返回完整的数据库对象,包含移动应用 UI 未显示的
敏感字段。移动应用在客户端过滤这些字段,但通过拦截 API 响应
可以完全访问它们。这暴露了任何已认证用户的 SSN 片段、内部
风险评分和 KYC 验证数据。

**发现的多余字段**:
- /accounts: routing_number, account_holder_ssn_last4, internal_risk_score,
  kyc_verification_status, linked_external_accounts(共 18 个多余字段)
- /transactions: merchant_id, terminal_id, authorization_code,
  processor_response(共 12 个多余字段)
- /users/me: last_login_ip, mfa_backup_codes_remaining, credit_score_band

**影响**:
已认证用户可以提取敏感财务数据、内部风险评估以及应用程序
本不打算暴露的 PII。结合 BOLA 漏洞,可以为所有用户提取这些数据。

**修复建议**:
1. 在服务器端使用 DTO/视图模型实施响应过滤,只包含客户端所需的字段
2. 对每个端点每个角色使用 GraphQL 字段级授权或 REST 响应 Schema
3. 在序列化层从 API 响应中移除敏感字段
4. 在 API 网关中实施响应 Schema 验证,去除未记录的字段
5. 添加自动化测试验证响应 Schema 与文档一致
```

Related Skills

testing-for-sensitive-data-exposure

9
from killvxk/cybersecurity-skills-zh

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

performing-sqlite-database-forensics

9
from killvxk/cybersecurity-skills-zh

对 SQLite 数据库执行取证分析,从空闲列表(Freelist)和 WAL 文件中恢复已删除记录,解码编码时间戳,并从浏览器历史、即时通讯应用和移动设备数据库中提取证据。

implementing-security-monitoring-with-datadog

9
from killvxk/cybersecurity-skills-zh

使用 Datadog 的云安全信息和事件管理(Cloud SIEM)、日志分析和威胁检测能力实施安全监控,识别并响应整个云基础设施中的安全事件。

implementing-pam-for-database-access

9
from killvxk/cybersecurity-skills-zh

为数据库系统(包括 Oracle、SQL Server、PostgreSQL 和 MySQL)部署特权访问管理。涵盖会话代理配置、凭据保管、查询审计、动态凭据生成和最小权限数据库角色。

implementing-gdpr-data-protection-controls

9
from killvxk/cybersecurity-skills-zh

《通用数据保护条例》(EU)2016/679(GDPR)是欧盟关于个人数据收集、处理、存储和传输的综合数据保护法律。本技能涵盖实施 GDPR 要求的技术和组织措施。

implementing-cloud-dlp-for-data-protection

9
from killvxk/cybersecurity-skills-zh

使用 Amazon Macie、Azure Information Protection 和 Google Cloud DLP API 实施云数据丢失预防(DLP),对云存储、数据库和数据管道中的敏感数据进行发现、分类和保护。

implementing-aws-macie-for-data-classification

9
from killvxk/cybersecurity-skills-zh

实施 Amazon Macie,利用机器学习和模式匹配自动发现、分类并保护 S3 存储桶中的敏感数据,包括 PII、金融数据和凭据检测。

implementing-aes-encryption-for-data-at-rest

9
from killvxk/cybersecurity-skills-zh

AES(高级加密标准)是由 NIST(FIPS 197)标准化的对称分组密码,用于保护机密和敏感数据。本技能涵盖在 GCM 模式下实现 AES-256 加密,用于加密静态文件和数据存储,包括正确的密钥派生、IV/nonce 管理和认证加密。

hunting-for-data-staging-before-exfiltration

9
from killvxk/cybersecurity-skills-zh

通过监控 7-Zip/RAR 压缩文件创建、异常临时目录访问、大文件合并以及暂存目录模式,借助 EDR 和进程遥测检测数据外泄前的暂存活动。

hunting-for-data-exfiltration-indicators

9
from killvxk/cybersecurity-skills-zh

通过网络流量分析狩猎数据外泄行为,检测异常数据流、DNS 隧道、云存储上传以及加密通道滥用。

exploiting-zerologon-vulnerability-cve-2020-1472

9
from killvxk/cybersecurity-skills-zh

利用 Netlogon 远程协议中的 Zerologon 漏洞(CVE-2020-1472),通过将机器账户密码重置为空来实现域控制器入侵。

exploiting-websocket-vulnerabilities

9
from killvxk/cybersecurity-skills-zh

在授权安全评估中测试 WebSocket 实现的身份验证绕过、跨站劫持、注入攻击和不安全消息处理。