mcpField
S
security-django

security-django

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

security-django について

security-djangoは、Djangoアプリケーションを監査する開発者向けのセキュリティスキルです。デプロイ設定、ミドルウェア、CSRF、一般的な脆弱性を扱い、安全なコード例と監査コマンドを示します。

主な機能

  1. 01重要設定の確認
  2. 02セキュリティミドルウェアとCSRFの確認
  3. 03一般的な脆弱性パターン
  4. 04より安全なコード例
  5. 05クイック監査コマンド
  6. 06デプロイ強化チェックリスト

活用シーン

  1. 01Django本番環境設定の監査
  2. 02CSRF除外とミドルウェアの確認
  3. 03インジェクションとパストラバーサルのリスク検出
  4. 04認証とDRF権限の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/igorwarzocha/opencode-workflows --skill security-django

インストール後、Claude Code で/security-djangoを入力して読み込まれたか確認します。

同梱ファイルscripts/scan.sh

詳細

Django アプリケーションにおける、重要な設定、セキュリティミドルウェア、CSRF 保護、一般的な脆弱性を対象とするセキュリティ監査パターンです。

重要な設定(settings.py)

SECRET_KEY
# ❌ CRITICAL: Hardcoded or committed
SECRET_KEY = 'django-insecure-abc123...'
SECRET_KEY = 'my-super-secret-key'

# ✓ From environment
import os
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']

# ✓ Or use django-environ
import environ
env = environ.Env()
SECRET_KEY = env('SECRET_KEY')

確認: SECRET_KEY は .env に設定されており、.env は .gitignore に含まれていますか?

DEBUG
# ❌ CRITICAL: Debug in production
DEBUG = True  # Exposes full stack traces, settings, SQL queries

# ✓ Environment-controlled
DEBUG = os.environ.get('DEBUG', 'False').lower() == 'true'
ALLOWED_HOSTS
# ❌ CRITICAL: Accept any host
ALLOWED_HOSTS = ['*']

# ❌ HIGH: Empty in production (500 errors, but still bad)
ALLOWED_HOSTS = []

# ✓ Explicit hosts
ALLOWED_HOSTS = ['example.com', 'www.example.com']

セキュリティミドルウェア

必須のミドルウェア
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',  # MUST be first!
    # ...
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

確認: SecurityMiddleware が含まれており、上位に配置されていますか?

セキュリティミドルウェアの設定
# ✓ Enable these in production
SECURE_BROWSER_XSS_FILTER = True  # Deprecated but harmless
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_HSTS_SECONDS = 31536000  # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_SSL_REDIRECT = True  # Force HTTPS
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

CSRF 保護

CSRF の無効化(重大)
# ❌ CRITICAL: Globally disabled
MIDDLEWARE = [
    # 'django.middleware.csrf.CsrfViewMiddleware',  # Commented out!
]

# ❌ HIGH: Decorator abuse
@csrf_exempt
def payment_webhook(request):  # MAY be OK for webhooks with other auth
    ...

@csrf_exempt
def update_profile(request):  # MUST NOT do this!
    ...

監査: @csrf_exempt を検索し、それぞれに正当な理由があることを確認してください。

CSRF の信頼済みオリジン(Django 4.0 以降)
# ❌ Too permissive
CSRF_TRUSTED_ORIGINS = ['https://*']

# ✓ Explicit
CSRF_TRUSTED_ORIGINS = ['https://example.com', 'https://admin.example.com']

一般的な脆弱性

SQL インジェクション
# ❌ Raw SQL with string formatting
User.objects.raw(f"SELECT * FROM users WHERE id = {user_id}")
cursor.execute(f"DELETE FROM logs WHERE date < '{date}'")

# ✓ Parameterized
User.objects.raw("SELECT * FROM users WHERE id = %s", [user_id])
cursor.execute("DELETE FROM logs WHERE date < %s", [date])

# ✓ ORM (safe by default)
User.objects.filter(id=user_id)
コマンドインジェクション
# ❌ User input in subprocess
import subprocess
subprocess.run(f"convert {user_filename} output.png", shell=True)
os.system(f"process {user_input}")

# ✓ Use arrays, avoid shell=True
subprocess.run(["convert", user_filename, "output.png"])
パストラバーサル
# ❌ User-controlled path
def download(request, filename):
    return FileResponse(open(f'uploads/{filename}', 'rb'))

# ✓ Validate path
import os
def download(request, filename):
    safe_name = os.path.basename(filename)
    filepath = os.path.join(settings.UPLOAD_DIR, safe_name)
    if not filepath.startswith(settings.UPLOAD_DIR):
        raise Http404()
    return FileResponse(open(filepath, 'rb'))
IDOR(安全でない直接オブジェクト参照)
# ❌ No ownership check
class DocumentView(View):
    def get(self, request, doc_id):
        doc = Document.objects.get(id=doc_id)
        return JsonResponse(doc.to_dict())

# ✓ Check ownership
class DocumentView(LoginRequiredMixin, View):
    def get(self, request, doc_id):
        doc = Document.objects.get(id=doc_id, owner=request.user)
        return JsonResponse(doc.to_dict())
認証デコレーターの不足
# ❌ No auth required
def admin_dashboard(request):
    return render(request, 'admin/dashboard.html', {'users': User.objects.all()})

# ✓ Auth required
@login_required
@user_passes_test(lambda u: u.is_staff)
def admin_dashboard(request):
    ...

Django REST Framework

# Check DRF settings
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        # ❌ SessionAuth without CSRF = vulnerable
        'rest_framework.authentication.SessionAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        # ❌ Allow any by default
        'rest_framework.permissions.AllowAny',
        # ✓ Require auth by default
        'rest_framework.permissions.IsAuthenticated',
    ],
}

クイック監査コマンド

# Check critical settings
rg "(SECRET_KEY|DEBUG|ALLOWED_HOSTS)" settings*.py

# Find csrf_exempt usage
rg "@csrf_exempt" . -g "*.py"

# Django deployment checklist (high signal)
python manage.py check --deploy

# Find raw SQL
rg "\.raw\(|cursor\.execute\(" . -g "*.py" -A 1

# Find subprocess/os.system
rg "(subprocess\.|os\.system|os\.popen)" . -g "*.py"

# Check for missing login_required
rg "^def " views.py | head -20  # Then check which have decorators

# Find shell=True
rg "shell\s*=\s*True" . -g "*.py"

セキュリティ強化チェックリスト

  • SECRET_KEY はハードコードせず、環境変数から取得する
  • 本番環境では DEBUG = False にする
  • ALLOWED_HOSTS を明示的に設定する(ワイルドカードは使用しない)
  • SecurityMiddleware を有効にして設定する
  • CSRF ミドルウェアを有効にする
  • SECURE_SSL_REDIRECT = True にする
  • SESSION_COOKIE_SECURE = True にする
  • CSRF_COOKIE_SECURE = True にする
  • 正当な理由なしに @csrf_exempt を使用しない
  • すべてのビューに適切な認証デコレーターを設定する
  • 文字列フォーマットを使った生の SQL を使用しない
  • DRF のデフォルト権限を IsAuthenticated にする

コメント