2025年12月19日金曜日

Python のプロジェクトでやっておくべきセキュリティテスト

Python のプロジェクトでやっておくべきセキュリティテスト

概要

簡単にできるのでとりあえず入れておいて損はしないはず

環境

  • macOS 15.7.2
  • Python 3.12.11
    • bandit 1.9.2
    • safety 3.7.0
    • sqlmap 1.8.2

bandit

  • pipenv install -d bandit
  • pipenv run bandit -r .

セキュアコードのチェックをしてくれます
os.system などインジェクションの危険があるコードを検知できます
random (セキュリティ用途) や assert などの使い方でも警告してくれます

safety

  • pipenv install -d safety
  • pipenv run safety scan

ライブラリなどのセキュリティチェックをしてくれます
アカウント登録が必要なのが辛いです
執筆時点では safety check が DEPRECATED ですが一応使えてこれならアカウント登録不要で使えます

zaproxy

Web アプリであれば導入しましょう
実際にアプリを起動してアプリに対してペネトレーションテストを実行してくれます

https://hawksnowlog.blogspot.com/2025/07/run-zaproxy-with-docker-penetration-test.html

nikto

こちらも Web アプリ用のペネトレーションテストです
zaproxy と結果が異なるので一応入れておいてもいいかもです

https://hawksnowlog.blogspot.com/2025/07/penetration-test-with-nikto-on-docker.html

sqlmap

SQLインジェクションに特化したペネトレーションテストです
公式の docker イメージなどはないようですが parootsec のスポンサードイメージがあるのでそれを使うのが簡単です

--level 5 --risk 3 --batch オプションを追加してもいいかもです

trivy

生成した docker イメージなどに対して行います
インストールされているモジュールやツールが脆弱性を含むバージョンでないかをチェックしてくれます

https://hawksnowlog.blogspot.com/2022/12/trivy.html

Metasploit

Python アプリと言うよりかはホストマシン側のペネトレーションテストです

https://hawksnowlog.blogspot.com/2025/08/how-to-run-metasploit-on-docker.html

fuzzing

特定の関数に対してメモリのオーバフローテストができます

https://hawksnowlog.blogspot.com/2025/12/python-fuzzing-test.html

Python 自体のユニットテスト

ユニットテストやシステムテストでインジェクション系のクエリを投げてテストします

mport pytest
from markupsafe import escape

def test_xss_prevention():
    """ユーザー入力が正しくエスケープされるか"""
    user_input = "<script>alert('xss')</script>"
    result = escape(user_input)
    assert "<script>" not in result
    assert "&lt;script&gt;" in result

def test_sql_injection_prevention(db):
    """SQLインジェクション対策の確認"""
    # SQLAlchemy のバインドパラメータを使用しているか
    malicious_input = "1' OR '1'='1"
    result = db.session.execute(
        text("SELECT * FROM users WHERE id = :id"),
        {"id": malicious_input}
    ).fetchall()
    # 結果は期待値と一致するか確認
    assert len(result) == 0

def test_password_hashing():
    """パスワードがハッシュ化されているか"""
    from werkzeug.security import check_password_hash, generate_password_hash
    password = "test_password_123"
    hashed = generate_password_hash(password)
    assert hashed != password
    assert check_password_hash(hashed, password)

def test_file_upload_validation():
    """ファイルアップロードが検証されるか"""
    from pathlib import Path
    import io
    # 許可されていないファイル型
    fake_pdf = io.BytesIO(b"not a real pdf")
    filename = "malicious.pdf"
    # バリデーション処理が拒否するか確認
    assert not validate_upload(fake_pdf, filename)

flask なら以下のような感じです

import pytest
from flask import Flask
from app import create_app

@pytest.fixture
def client():
    app = create_app()
    app.config['TESTING'] = True
    with app.test_client() as client:
        yield client

def test_csrf_protection(client):
    """CSRF トークン検証"""
    response = client.get('/form')
    assert 'csrf_token' in response.data.decode()
    
    # CSRF トークンなしで POST → 403 エラー
    response = client.post('/form', data={'field': 'value'})
    assert response.status_code == 403

def test_authentication_required(client):
    """認証なしで保護されたエンドポイントアクセス"""
    response = client.get('/dashboard')
    assert response.status_code == 302  # リダイレクト
    assert '/login' in response.location

def test_path_traversal_prevention(client):
    """パストラバーサル攻撃の防止"""
    response = client.get('/files?file=../../etc/passwd')
    assert response.status_code == 403 or response.status_code == 404

def test_injection_attacks(client):
    """SQLインジェクション攻撃の防止"""
    malicious = "1' OR '1'='1'; DROP TABLE users; --"
    response = client.get(f'/search?q={malicious}')
    # 結果が期待通りで、テーブルが削除されていないか確認
    assert response.status_code == 200
    assert 'results' in response.json

有料もしくはアカウント登録必要

SonarQube

Web GUI でテストできます
導入が面倒そうです

Burp Suite

クライアント GUI でテストできます
ペネトレーションテストツールです
かなり複雑な攻撃までできるようです

SBOM (snyk)

trivy のように CLI でチェックできます

最後に

セキュリティ系のテストは一つではなく複数を組み合わせてやることで強度が増します

0 件のコメント:

コメントを投稿