用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/killvxk/cybersecurity-skills-zh --skill detecting-broken-object-property-level-authorization命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
通过分析 Zeek dns.log 中的高熵子域名查询、超量查询量、超长查询长度以及异常 DNS 记录类型,检测 DNS 隧道和数据外泄中的隐蔽通道通信。适用于:当需要狩猎基于 DNS 的 C2 或数据外泄通道、调查异常 DNS 查询模式、或响应涉及 DNS 隧道工具(iodine、dnscat2、DNSExfiltrator)的威胁情报时使用。
实施 Google 的 BeyondCorp 零信任访问模型,通过 IAP、Access Context Manager 和 Chrome Enterprise Premium,消除网络边界的隐式信任,强制执行基于身份的访问控制,实现无 VPN 的安全应用访问。适用于将传统 VPN 替换为零信任架构、部署 Identity-Aware Proxy、配置设备信任策略、或为远程办公实施上下文感知访问控制时使用。
在授权的安全评估过程中,使用 Burp Suite 的扫描器、Intruder 和 Repeater 工具识别和验证跨站脚本(XSS)漏洞。适用于 Web 应用渗透测试中检测反射型、存储型和 DOM 型 XSS,验证自动化扫描器报告的 XSS 发现,以及评估 CSP 和 XSS 过滤器的有效性时使用。
基于 SOC 职业分类
正在显示 SKILL.md
| name | detecting-broken-object-property-level-authorization |
| description | 检测和测试OWASP API3:2023对象属性级授权失效(BOPLA)漏洞,包括过度数据暴露和批量赋值攻击。 |
| domain | cybersecurity |
| subdomain | api-security |
| tags | ["api-security","bopla","owasp-api3","mass-assignment","excessive-data-exposure","property-level-authorization","api-testing","penetration-testing"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
对象属性级授权失效(Broken Object Property Level Authorization,BOPLA)被OWASP API安全Top 10归类为API3:2023,结合了两类相关漏洞:过度数据暴露(API返回超出所需的数据)和批量赋值(Mass Assignment,API接受超出预期的数据)。即使API正确地执行了对象级授权,也可能无法控制用户对对象特定属性的读写权限。攻击者利用此漏洞从API响应中读取敏感属性,或向请求体中注入额外属性来修改其无权访问的字段。
API返回的对象属性超出客户端所需:
// GET /api/v1/users/123
// 响应包含UI未显示的敏感字段:
{
"id": 123,
"username": "john_doe",
"email": "john@example.com",
"name": "John Doe",
"ssn": "123-45-6789", // 敏感 - UI不需要
"salary": 95000, // 敏感 - UI不需要
"internal_notes": "VIP client", // 内部 - 不应暴露
"password_hash": "$2b$12...", // 严重 - 永远不应暴露
"role": "admin", // 可能暴露权限信息
"created_by": "system_admin", // 内部元数据
"credit_card_last4": "4242" // PCI合规违规
}
API未过滤地将客户端提供的数据绑定到内部对象属性:
// 普通用户更新请求
PUT /api/v1/users/123
Content-Type: application/json
{
"name": "John Updated",
"email": "new@example.com",
"role": "admin", // 攻击者注入:权限提升
"is_verified": true, // 攻击者注入:绕过验证
"discount_rate": 100, // 攻击者注入:业务逻辑滥用
"account_balance": 999999 // 攻击者注入:金融欺诈
}
#!/usr/bin/env python3
"""BOPLA漏洞扫描器
测试API是否存在对象属性级授权失效(BOPLA)漏洞,
包括过度数据暴露和批量赋值。
"""
import requests
import json
import sys
from typing import Dict, List, Optional, Set
from dataclasses import dataclass, field
from copy import deepcopy
@dataclass
class BOPLAFinding:
endpoint: str
method: str
vulnerability_type: str # "excessive_exposure" 或 "mass_assignment"
severity: str
property_name: str
details: str
class BOPLAScanner:
SENSITIVE_PROPERTY_PATTERNS = {
"critical": [
"password", "password_hash", "secret", "token", "api_key",
"private_key", "secret_key", "access_token", "refresh_token",
],
"high": [
"ssn", "social_security", "tax_id", "credit_card", "card_number",
"cvv", "bank_account", "routing_number",
],
"medium": [
"salary", , , ,
, , , ,
, , , , ,
],
: [
, , , , ,
, , ,
]
}
MASS_ASSIGNMENT_FIELDS = [
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, ),
(, [, , ]),
(, ),
(, ),
(, ),
]
():
.base_url = base_url.rstrip()
.auth_headers = auth_headers
.findings: [BOPLAFinding] = []
() -> [BOPLAFinding]:
findings = []
url =
:
response = requests.get(url, headers=.auth_headers, timeout=)
response.status_code != :
findings
data = response.json()
objects = data (data, ) [data]
(data, ) data:
objects = data[] (data[], ) [data[]]
obj objects[:]:
(obj, ):
response_fields = (._flatten_keys(obj))
unexpected_fields = response_fields - expected_fields
field_name unexpected_fields:
severity = ._classify_sensitivity(field_name)
severity:
finding = BOPLAFinding(
endpoint=endpoint,
method=,
vulnerability_type=,
severity=severity,
property_name=field_name,
details=
)
findings.append(finding)
.findings.append(finding)
(requests.exceptions.RequestException, json.JSONDecodeError):
findings
() -> [BOPLAFinding]:
findings = []
url =
original_data :
:
response = requests.get(url, headers=.auth_headers, timeout=)
response.status_code == :
original_data = response.json()
:
original_data = {}
(requests.exceptions.RequestException, json.JSONDecodeError):
original_data = {}
field_name, injected_value .MASS_ASSIGNMENT_FIELDS:
field_name original_data:
original_value = original_data[field_name]
original_value == injected_value:
test_data = deepcopy(original_data)
test_data[field_name] = injected_value
headers = {**.auth_headers, : }
:
method == :
response = requests.put(url, json=test_data,
headers=headers, timeout=)
method == :
response = requests.patch(url, json={field_name: injected_value},
headers=headers, timeout=)
method == :
response = requests.post(url, json=test_data,
headers=headers, timeout=)
response.status_code (, , ):
verify_response = requests.get(url, headers=.auth_headers, timeout=)
verify_response.status_code == :
updated_data = verify_response.json()
updated_data.get(field_name) == injected_value:
finding = BOPLAFinding(
endpoint=endpoint,
method=method,
vulnerability_type=,
severity= field_name [, , ]
,
property_name=field_name,
details=
)
findings.append(finding)
.findings.append(finding)
field_name original_data:
restore_data = {field_name: original_data[field_name]}
requests.patch(url, json=restore_data,
headers=headers, timeout=)
requests.exceptions.RequestException:
findings
() -> [BOPLAFinding]:
findings = []
url =
introspection =
:
response = requests.post(
url,
json={: introspection},
headers=.auth_headers,
timeout=
)
response.status_code == :
data = response.json()
data:
finding = BOPLAFinding(
endpoint=graphql_endpoint,
method=,
vulnerability_type=,
severity=,
property_name=,
details=
)
findings.append(finding)
.findings.append(finding)
requests.exceptions.RequestException:
findings
() -> []:
keys = []
key, value obj.items():
full_key = prefix key
keys.append(full_key)
(value, ):
keys.extend(._flatten_keys(value, full_key))
keys
() -> []:
lower_name = field_name.lower().split()[-]
severity, patterns .SENSITIVE_PROPERTY_PATTERNS.items():
pattern patterns:
pattern lower_name:
severity.upper()
() -> :
{
: (.findings),
: {
: ([f f .findings
f.vulnerability_type == ]),
: ([f f .findings
f.vulnerability_type == ]),
},
: {
: ([f f .findings f.severity == ]),
: ([f f .findings f.severity == ]),
: ([f f .findings f.severity == ]),
: ([f f .findings f.severity == ]),
},
: [
{
: f.endpoint,
: f.method,
: f.vulnerability_type,
: f.severity,
: f.property_name,
: f.details,
}
f .findings
]
}
# 服务端:显式属性白名单
class UserSerializer:
# 只暴露这些字段 - 永远不要使用to_json()或to_dict()
PUBLIC_FIELDS = ['id', 'username', 'name', 'avatar_url']
OWNER_FIELDS = PUBLIC_FIELDS + ['email', 'phone', 'preferences']
ADMIN_FIELDS = OWNER_FIELDS + ['role', 'created_at', 'last_login']
def serialize(self, user, requesting_user):
if requesting_user.is_admin:
fields = self.ADMIN_FIELDS
elif requesting_user.id == user.id:
fields = self.OWNER_FIELDS
else:
fields = self.PUBLIC_FIELDS
return {field: getattr(user, field) for field in fields}
# 批量赋值保护 - 可写字段的显式白名单
WRITABLE_FIELDS = {'name', 'email', 'phone', 'avatar_url', 'preferences'}
def update_user(user_id, request_data, requesting_user):
# 过滤掉不在白名单中的字段
safe_data = {k: v for k, v in request_data.items() if k in WRITABLE_FIELDS}
# 仅使用安全数据应用更新
User.objects.filter(id=user_id).update(**safe_data)