mcpField
S
software-data-integrity-failures

software-data-integrity-failures

github.com/scholarly360セキュリティ2244 回インストール29 週間前に更新
リポジトリ

software-data-integrity-failures について

FastAPI と Flask アプリケーションのソフトウェアおよびデータ完全性リスクを調べる、Python 開発者向けのセキュリティ監査スキルです。安全でないデシリアライズ、マスアサインメント、未検証の外部リソースや更新など、実行時の脅威を扱います。

主な機能

  1. 01危険なデシリアライズパターンの検出
  2. 02マスアサインメントのリスク確認
  3. 03外部アセットの SRI 確認
  4. 04更新とダウンロードの検証監査
  5. 05テストチェックリストとスキャンコマンド

活用シーン

  1. 01Flask または 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()pickle を使用Redis/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 アプリが外部 CDN からスクリプトやスタイルシートを読み込む HTML テンプレートをレンダリングする場合、CDN の侵害による悪意あるコードの挿入を防ぐため、対象リソースに SRI ハッシュを含める必要があります。

脆弱な 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.load() の代わりに yaml.safe_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完全性チェックを行わないコードのダウンロード検証なしの自動アップデート

参考資料

コメント