关于 software-data-integrity-failures
面向 Python 开发者的安全审计技能,用于检查 FastAPI 和 Flask 应用的软件与数据完整性风险,重点涵盖运行时反序列化、批量赋值及未经验证的资源和更新。
主要功能
- 01标记不安全的反序列化模式
- 02检查批量赋值风险
- 03审查外部资源的 SRI
- 04检查更新与下载验证
- 05提供测试清单和扫描命令
适用场景
- 01审计 Flask 或 FastAPI 代码库
- 02检查不可信数据的反序列化
- 03核查外部脚本的完整性哈希
- 04为更新流程添加完整性验证
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ scholarly360/ owasp-top10-web-skills --skill software-data-integrity-failures安装后在 Claude Code 中输入/software-data-integrity-failures确认已加载。
附带文件references/deserialization-exploits.md
详细介绍
A08:2025 — 软件或数据完整性故障
概述
OWASP 排名: #8(2025 年) | 涵盖的 CWE: 14 | 平均发生率: 2.75%
此类别关注未能验证自身环境中的软件、代码和数据制品的完整性——这不同于 A03 对上游供应链的关注。核心问题是:你能否信任正在加载、反序列化或执行的内容?
与 A03(供应链)的主要区别:
- A03 = 上游完整性(你的依赖项、CI/CD 管道)
- A08 = 运行时完整性(运行时实际反序列化、包含或自动更新的内容)
Python 的关键风险领域
1. 不安全的反序列化 — Python 特有的首要风险
对不可信输入调用 pickle.loads() 等同于通过 __reduce__ 执行任意代码。这是 Python 中最危险的 A08 攻击途径。
需要标记的危险函数/模块:
| 模块 / 函数 | 风险 | 安全替代方案 |
|---|---|---|
pickle.loads() / pickle.load() | 通过 __reduce__ 实现 RCE | JSON + Pydantic |
cPickle.loads() | 与 pickle 相同 | JSON + Pydantic |
dill.loads() | pickle 的超集,具有相同的 RCE 风险 | JSON + Pydantic |
jsonpickle.decode() | 反序列化 Python 对象 | 仅使用 json.loads() |
shelve.open() | 底层依赖 pickle | Redis/SQL 存储 |
yaml.load(data, Loader=None) | 通过 !!python/object 执行代码 | yaml.safe_load() |
numpy.load(f, allow_pickle=True) | 通过 pickle 化数组实现 RCE | allow_pickle=False |
torch.load(f) | 默认由 pickle 支持 | weights_only=True |
检测模式(静态分析):
# Flag any of these patterns in source code
DANGEROUS_PATTERNS = [
r'pickle\.loads?\(',
r'cPickle\.loads?\(',
r'dill\.loads?\(',
r'jsonpickle\.decode\(',
r'shelve\.open\(',
r'yaml\.load\([^)]*(?!safe_load)',
r'numpy\.load\([^)]*allow_pickle\s*=\s*True',
r'torch\.load\([^)]*(?!weights_only\s*=\s*True)',
]
如果无法避免使用 pickle — HMAC 完整性检查:
import hmac, hashlib, pickle, os
SECRET = os.environ["PICKLE_HMAC_SECRET"].encode()
def safe_serialize(obj) -> bytes:
data = pickle.dumps(obj)
mac = hmac.new(SECRET, data, hashlib.sha256).digest()
return mac + data # prepend 32-byte MAC
def safe_deserialize(payload: bytes):
mac, data = payload[:32], payload[32:]
expected = hmac.new(SECRET, data, hashlib.sha256).digest()
if not hmac.compare_digest(mac, expected):
raise ValueError("Integrity check failed — data tampered")
return pickle.loads(data)
2. 批量赋值(CWE-915)
当 request.json 或表单数据未经字段筛选就直接传入 ORM .update() 时会发生此问题,攻击者因此可以设置 is_admin=True 或 role="superuser" 等字段。
Flask — 易受攻击的模式:
# ❌ DANGEROUS — attacker can inject any field
user = User.query.get(user_id)
user.__dict__.update(request.json)
db.session.commit()
# Also dangerous:
User.query.filter_by(id=user_id).update(request.json)
Flask — 安全模式:
# ✅ SAFE — explicit allowlist
ALLOWED_FIELDS = {"name", "email", "bio"}
data = {k: v for k, v in request.json.items() if k in ALLOWED_FIELDS}
User.query.filter_by(id=user_id).update(data)
FastAPI — Pydantic 默认可防止批量赋值:
# ✅ FastAPI with Pydantic — only declared fields accepted
class UserUpdate(BaseModel):
name: str | None = None
email: str | None = None
bio: str | None = None
# is_admin, role etc. cannot be set — they're not in the schema
@router.patch("/users/{user_id}")
async def update_user(user_id: int, body: UserUpdate, db: Session = Depends(get_db)):
db.query(User).filter(User.id == user_id).update(body.model_dump(exclude_unset=True))
检测模式: 在 Flask 中,扫描 request.json 或 request.form 是否未经中间的允许列表筛选,就流入 .update()、__dict__.update() 或 ORM 批量更新调用。
3. 外部脚本/样式表的子资源完整性(SRI)
如果 Flask/FastAPI 应用渲染的 HTML 模板会从外部 CDN 加载脚本或样式表,这些资源必须包含 SRI 哈希,以防 CDN 遭到入侵后注入恶意代码。
存在漏洞的 Jinja2 模板:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
安全的 Jinja2 模板:
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous">
</script>
如何生成 SRI 哈希:
# Using openssl
curl -sL https://cdn.example.com/lib.js | openssl dgst -sha384 -binary | openssl base64 -A
# Or use srihash.org / unpkg.com automatically provides them
检测: 扫描 Jinja2/HTML 模板,查找缺少 integrity= 属性的 <script src="https://..."> 和 <link href="https://..."> 标签。
4. 未经验证的自动更新(CWE-494)
下载并执行代码/配置更新,却不验证其加密签名的应用容易遭受中间人攻击。
需要标记的模式:
# ❌ Downloads and executes without verification
import urllib.request, subprocess
urllib.request.urlretrieve("https://example.com/update.sh", "/tmp/update.sh")
subprocess.run(["bash", "/tmp/update.sh"])
# ❌ Loads remote config without integrity check
import json, urllib.request
config = json.loads(urllib.request.urlopen("https://config.example.com/settings.json").read())
安全模式 — 签名验证:
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
import urllib.request
def download_and_verify(url: str, sig_url: str, public_key_path: str) -> bytes:
data = urllib.request.urlopen(url).read()
sig = urllib.request.urlopen(sig_url).read()
with open(public_key_path, "rb") as f:
pubkey = serialization.load_pem_public_key(f.read())
pubkey.verify(sig, data, padding.PKCS1v15(), hashes.SHA256()) # raises on failure
return data
测试清单
审核 FastAPI 或 Flask 应用是否符合 A08 要求时,请使用此清单:
反序列化
- 不对不可信输入调用
pickle.loads()/pickle.load() - 不对不可信输入调用
cPickle、dill、jsonpickle.decode() - 使用
yaml.safe_load()而不是yaml.load() - 调用
numpy.load()时设置allow_pickle=False - 调用
torch.load()时设置weights_only=True - 不将
shelve用于不可信键/数据 - 如果无法避免使用 pickle:已实现 HMAC 预验证
批量赋值
- Flask:不将
request.json直接传入 ORM.update(),除非经过允许列表筛选 - Flask:不存在
model.__dict__.update(untrusted_data)模式 - FastAPI:所有请求正文均使用 Pydantic 模型(默认可防止批量赋值)
- 公开的更新架构中不包含特权字段(
is_admin、role、balance)
外部完整性
- 所有外部
<script>标签都具有integrity=SRI 属性 - 所有外部
<link rel="stylesheet">标签都具有integrity=SRI 属性 - 远程下载内容在执行前均经过加密签名或哈希验证
- 不对远程获取的内容使用动态
eval()或exec()
CI/CD 完整性(与 A03 的边界)
- 所有部署配置/脚本变更都必须经过代码审查
- 构建产物均已签名,并在部署前验证签名
- CI/CD 密钥不可供来自分叉仓库的拉取请求流水线访问
自动化扫描工具
| 工具 | 检测内容 | 运行方式 |
|---|---|---|
| Bandit | pickle、yaml.load、subprocess、eval | bandit -r . -t B301,B302,B506 |
| Semgrep | 反序列化、批量赋值模式 | semgrep --config=p/python |
| pip-audit | 存在已知漏洞的反序列化库 | pip-audit |
| 手动 grep | 快速扫描危险函数 | 参见第 1 节中的模式 |
A08 的 Bandit 规则 ID:
B301— 使用pickleB302— 使用marshal(风险类似)B506—yaml.load未使用安全加载器B403— 导入pickle(仅供参考)
关键 CWE
| CWE | 描述 | 主要攻击途径 |
|---|---|---|
| CWE-502 | 对不可信数据进行反序列化 | pickle、yaml、jsonpickle |
| CWE-915 | 对动态确定的对象属性进行控制不当的修改 | 批量赋值 |
| CWE-829 | 引入来自不可信控制域的功能 | 未使用 SRI 的 CDN 脚本 |
| CWE-345 | 数据真实性验证不足 | 缺少 HMAC/签名检查 |
| CWE-494 | 下载代码时未进行完整性检查 | 未经验证的自动更新 |
参考资料
- OWASP A08:2025 — 软件和数据完整性失效
- Python Pickle 安全性
- SRI 哈希生成器
- 适用于 Python 的 Bandit SAST
- 有关漏洞利用 PoC 和深入分析,请参阅
references/deserialization-exploits.md