mcpField
S
software-data-integrity-failures

software-data-integrity-failures

github.com/scholarly360安全2244 次安装29 周前更新
代码仓库

关于 software-data-integrity-failures

面向 Python 开发者的安全审计技能,用于检查 FastAPI 和 Flask 应用的软件与数据完整性风险,重点涵盖运行时反序列化、批量赋值及未经验证的资源和更新。

主要功能

  1. 01标记不安全的反序列化模式
  2. 02检查批量赋值风险
  3. 03审查外部资源的 SRI
  4. 04检查更新与下载验证
  5. 05提供测试清单和扫描命令

适用场景

  1. 01审计 Flask 或 FastAPI 代码库
  2. 02检查不可信数据的反序列化
  3. 03核查外部脚本的完整性哈希
  4. 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__ 实现 RCEJSON + Pydantic
cPickle.loads()与 pickle 相同JSON + Pydantic
dill.loads()pickle 的超集,具有相同的 RCE 风险JSON + Pydantic
jsonpickle.decode()反序列化 Python 对象仅使用 json.loads()
shelve.open()底层依赖 pickleRedis/SQL 存储
yaml.load(data, Loader=None)通过 !!python/object 执行代码yaml.safe_load()
numpy.load(f, allow_pickle=True)通过 pickle 化数组实现 RCEallow_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 密钥不可供来自分叉仓库的拉取请求流水线访问

自动化扫描工具

工具检测内容运行方式
Banditpickle、yaml.load、subprocess、evalbandit -r . -t B301,B302,B506
Semgrep反序列化、批量赋值模式semgrep --config=p/python
pip-audit存在已知漏洞的反序列化库pip-audit
手动 grep快速扫描危险函数参见第 1 节中的模式

A08 的 Bandit 规则 ID:

  • B301 — 使用 pickle
  • B302 — 使用 marshal(风险类似)
  • B506 — yaml.load 未使用安全加载器
  • B403 — 导入 pickle(仅供参考)

关键 CWE

CWE描述主要攻击途径
CWE-502对不可信数据进行反序列化pickle、yaml、jsonpickle
CWE-915对动态确定的对象属性进行控制不当的修改批量赋值
CWE-829引入来自不可信控制域的功能未使用 SRI 的 CDN 脚本
CWE-345数据真实性验证不足缺少 HMAC/签名检查
CWE-494下载代码时未进行完整性检查未经验证的自动更新

参考资料

评论

支持 Markdown