Source profileQuality 78/100

affaan-m/ECC/docs/ja-JP/skills/django-security/SKILL.md

django-security

Django security best practices, authentication, authorization, CSRF protection, SQL injection prevention, XSS prevention, and secure deployment configurations.

Source repository stars
234,327
Declared platforms
0
Static risk flags
1
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

一般的な脆弱性から保護するためのDjangoアプリケーションの包括的なセキュリティガイドライン。

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/ja-JP/skills/django-security"
    Safe inspection promptEditorial

    Inspect the Agent Skill "django-security" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/ja-JP/skills/django-security/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      いつ有効化するか

      Django認証と認可を設定するとき

      Django認証と認可を設定するときユーザー権限とロールを実装するとき本番セキュリティ設定を構成するとき
    2. 02

      核となるセキュリティ設定

      Review the “核となるセキュリティ設定” section in the pinned source before continuing.

      Review and apply the “核となるセキュリティ設定” source section.
    3. 03

      本番設定の構成

      Review the “本番設定の構成” section in the pinned source before continuing.

      Review and apply the “本番設定の構成” source section.
    4. 04

      settings/production.py

      DEBUG = False 重要: 本番環境では絶対にTrueにしない

      DEBUG = False 重要: 本番環境では絶対にTrueにしないALLOWEDHOSTS = os.environ.get('ALLOWEDHOSTS', '').split(',')
    5. 05

      セキュリティヘッダー

      SECURESSLREDIRECT = True SESSIONCOOKIESECURE = True CSRFCOOKIESECURE = True SECUREHSTSSECONDS = 31536000 1年 SECUREHSTSINCLUDESUBDOMAINS = True SECUREHSTSPRELOAD = True SECURECONTENTTYPENOSNIFF = True SECUREBROWSERXSSFILTER = True XFRAMEOPTIONS = 'DENY'

      SECURESSLREDIRECT = True SESSIONCOOKIESECURE = True CSRFCOOKIESECURE = True SECUREHSTSSECONDS = 31536000 1年 SECUREHSTSINCLUDESUBDOMAINS = True SECUREHSTSPRELOAD = True SECURECONTENTTYPENOSNIFF = True SECUREBROWSERXSSFIL…

    Permission review

    Static risk signals and limitations

    Network access

    medium · line 336

    The documentation includes network, browsing, or remote request actions.

    CSRF_TRUSTED_ORIGINS = ['https://example.com'] # 信頼されたドメイン

    Network access

    medium · line 361

    The documentation includes network, browsing, or remote request actions.

    fetch('/api/endpoint/', {

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score78/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/ja-JP/skills/django-security/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Django セキュリティベストプラクティス

    一般的な脆弱性から保護するためのDjangoアプリケーションの包括的なセキュリティガイドライン。

    いつ有効化するか

    • Django認証と認可を設定するとき
    • ユーザー権限とロールを実装するとき
    • 本番セキュリティ設定を構成するとき
    • Djangoアプリケーションのセキュリティ問題をレビューするとき
    • Djangoアプリケーションを本番環境にデプロイするとき

    核となるセキュリティ設定

    本番設定の構成

    # settings/production.py
    import os
    
    DEBUG = False  # 重要: 本番環境では絶対にTrueにしない
    
    ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')
    
    # セキュリティヘッダー
    SECURE_SSL_REDIRECT = True
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SECURE = True
    SECURE_HSTS_SECONDS = 31536000  # 1年
    SECURE_HSTS_INCLUDE_SUBDOMAINS = True
    SECURE_HSTS_PRELOAD = True
    SECURE_CONTENT_TYPE_NOSNIFF = True
    SECURE_BROWSER_XSS_FILTER = True
    X_FRAME_OPTIONS = 'DENY'
    
    # HTTPSとクッキー
    SESSION_COOKIE_HTTPONLY = True
    CSRF_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SAMESITE = 'Lax'
    CSRF_COOKIE_SAMESITE = 'Lax'
    
    # シークレットキー(環境変数経由で設定する必要があります)
    SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
    if not SECRET_KEY:
        raise ImproperlyConfigured('DJANGO_SECRET_KEY environment variable is required')
    
    # パスワード検証
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
            'OPTIONS': {
                'min_length': 12,
            }
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    

    認証

    カスタムユーザーモデル

    # apps/users/models.py
    from django.contrib.auth.models import AbstractUser
    from django.db import models
    
    class User(AbstractUser):
        """より良いセキュリティのためのカスタムユーザーモデル。"""
    
        email = models.EmailField(unique=True)
        phone = models.CharField(max_length=20, blank=True)
    
        USERNAME_FIELD = 'email'  # メールをユーザー名として使用
        REQUIRED_FIELDS = ['username']
    
        class Meta:
            db_table = 'users'
            verbose_name = 'User'
            verbose_name_plural = 'Users'
    
        def __str__(self):
            return self.email
    
    # settings/base.py
    AUTH_USER_MODEL = 'users.User'
    

    パスワードハッシング

    # デフォルトではDjangoはPBKDF2を使用。より強力なセキュリティのために:
    PASSWORD_HASHERS = [
        'django.contrib.auth.hashers.Argon2PasswordHasher',
        'django.contrib.auth.hashers.PBKDF2PasswordHasher',
        'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
        'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    ]
    

    セッション管理

    # セッション設定
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # または 'db'
    SESSION_CACHE_ALIAS = 'default'
    SESSION_COOKIE_AGE = 3600 * 24 * 7  # 1週間
    SESSION_SAVE_EVERY_REQUEST = False
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # より良いUXですが、セキュリティは低い
    

    認可

    パーミッション

    # models.py
    from django.db import models
    from django.contrib.auth.models import Permission
    
    class Post(models.Model):
        title = models.CharField(max_length=200)
        content = models.TextField()
        author = models.ForeignKey(User, on_delete=models.CASCADE)
    
        class Meta:
            permissions = [
                ('can_publish', 'Can publish posts'),
                ('can_edit_others', 'Can edit posts of others'),
            ]
    
        def user_can_edit(self, user):
            """ユーザーがこの投稿を編集できるかチェック。"""
            return self.author == user or user.has_perm('app.can_edit_others')
    
    # views.py
    from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
    from django.views.generic import UpdateView
    
    class PostUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
        model = Post
        permission_required = 'app.can_edit_others'
        raise_exception = True  # リダイレクトの代わりに403を返す
    
        def get_queryset(self):
            """ユーザーが自分の投稿のみを編集できるようにする。"""
            return Post.objects.filter(author=self.request.user)
    

    カスタムパーミッション

    # permissions.py
    from rest_framework import permissions
    
    class IsOwnerOrReadOnly(permissions.BasePermission):
        """所有者のみがオブジェクトを編集できるようにする。"""
    
        def has_object_permission(self, request, view, obj):
            # 読み取り権限は任意のリクエストに許可
            if request.method in permissions.SAFE_METHODS:
                return True
    
            # 書き込み権限は所有者のみ
            return obj.author == request.user
    
    class IsAdminOrReadOnly(permissions.BasePermission):
        """管理者は何でもでき、他は読み取りのみ。"""
    
        def has_permission(self, request, view):
            if request.method in permissions.SAFE_METHODS:
                return True
            return request.user and request.user.is_staff
    
    class IsVerifiedUser(permissions.BasePermission):
        """検証済みユーザーのみを許可。"""
    
        def has_permission(self, request, view):
            return request.user and request.user.is_authenticated and request.user.is_verified
    

    ロールベースアクセス制御(RBAC)

    # models.py
    from django.contrib.auth.models import AbstractUser, Group
    
    class User(AbstractUser):
        ROLE_CHOICES = [
            ('admin', 'Administrator'),
            ('moderator', 'Moderator'),
            ('user', 'Regular User'),
        ]
        role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user')
    
        def is_admin(self):
            return self.role == 'admin' or self.is_superuser
    
        def is_moderator(self):
            return self.role in ['admin', 'moderator']
    
    # Mixin
    class AdminRequiredMixin:
        """管理者ロールを要求するMixin。"""
    
        def dispatch(self, request, *args, **kwargs):
            if not request.user.is_authenticated or not request.user.is_admin():
                from django.core.exceptions import PermissionDenied
                raise PermissionDenied
            return super().dispatch(request, *args, **kwargs)
    

    SQLインジェクション防止

    Django ORM保護

    # GOOD: Django ORMは自動的にパラメータをエスケープ
    def get_user(username):
        return User.objects.get(username=username)  # 安全
    
    # GOOD: raw()でパラメータを使用
    def search_users(query):
        return User.objects.raw('SELECT * FROM users WHERE username = %s', [query])
    
    # BAD: ユーザー入力を直接補間しない
    def get_user_bad(username):
        return User.objects.raw(f'SELECT * FROM users WHERE username = {username}')  # 脆弱!
    
    # GOOD: 適切なエスケープでfilterを使用
    def get_users_by_email(email):
        return User.objects.filter(email__iexact=email)  # 安全
    
    # GOOD: 複雑なクエリにQオブジェクトを使用
    from django.db.models import Q
    def search_users_complex(query):
        return User.objects.filter(
            Q(username__icontains=query) |
            Q(email__icontains=query)
        )  # 安全
    

    raw()での追加セキュリティ

    # 生のSQLを使用する必要がある場合は、常にパラメータを使用
    User.objects.raw(
        'SELECT * FROM users WHERE email = %s AND status = %s',
        [user_input_email, status]
    )
    

    XSS防止

    テンプレートエスケープ

    {# Djangoはデフォルトで変数を自動エスケープ - 安全 #}
    {{ user_input }}  {# エスケープされたHTML #}
    
    {# 信頼できるコンテンツのみを明示的に安全とマーク #}
    {{ trusted_html|safe }}  {# エスケープされない #}
    
    {# 安全なHTMLのためにテンプレートフィルタを使用 #}
    {{ user_input|escape }}  {# デフォルトと同じ #}
    {{ user_input|striptags }}  {# すべてのHTMLタグを削除 #}
    
    {# JavaScriptエスケープ #}
    <script>
        var username = {{ username|escapejs }};
    </script>
    

    安全な文字列処理

    from django.utils.safestring import mark_safe
    from django.utils.html import escape
    
    # BAD: エスケープせずにユーザー入力を安全とマークしない
    def render_bad(user_input):
        return mark_safe(user_input)  # 脆弱!
    
    # GOOD: 最初にエスケープ、次に安全とマーク
    def render_good(user_input):
        return mark_safe(escape(user_input))
    
    # GOOD: 変数を持つHTMLにformat_htmlを使用
    from django.utils.html import format_html
    
    def greet_user(username):
        return format_html('<span class="user">{}</span>', escape(username))
    

    HTTPヘッダー

    # settings.py
    SECURE_CONTENT_TYPE_NOSNIFF = True  # MIMEスニッフィングを防止
    SECURE_BROWSER_XSS_FILTER = True  # XSSフィルタを有効化
    X_FRAME_OPTIONS = 'DENY'  # クリックジャッキングを防止
    
    # カスタムミドルウェア
    from django.conf import settings
    
    class SecurityHeaderMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            response = self.get_response(request)
            response['X-Content-Type-Options'] = 'nosniff'
            response['X-Frame-Options'] = 'DENY'
            response['X-XSS-Protection'] = '1; mode=block'
            response['Content-Security-Policy'] = "default-src 'self'"
            return response
    

    CSRF保護

    デフォルトCSRF保護

    # settings.py - CSRFはデフォルトで有効
    CSRF_COOKIE_SECURE = True  # HTTPSでのみ送信
    CSRF_COOKIE_HTTPONLY = True  # JavaScriptアクセスを防止
    CSRF_COOKIE_SAMESITE = 'Lax'  # 一部のケースでCSRFを防止
    CSRF_TRUSTED_ORIGINS = ['https://example.com']  # 信頼されたドメイン
    
    # テンプレート使用
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit">Submit</button>
    </form>
    
    # AJAXリクエスト
    function getCookie(name) {
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            const cookies = document.cookie.split(';');
            for (let i = 0; i < cookies.length; i++) {
                const cookie = cookies[i].trim();
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    
    fetch('/api/endpoint/', {
        method: 'POST',
        headers: {
            'X-CSRFToken': getCookie('csrftoken'),
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(data)
    });
    

    ビューの除外(慎重に使用)

    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt  # 絶対に必要な場合のみ使用!
    def webhook_view(request):
        # 外部サービスからのWebhook
        pass
    

    ファイルアップロードセキュリティ

    ファイル検証

    import os
    from django.core.exceptions import ValidationError
    
    def validate_file_extension(value):
        """ファイル拡張子を検証。"""
        ext = os.path.splitext(value.name)[1]
        valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.pdf']
        if not ext.lower() in valid_extensions:
            raise ValidationError('Unsupported file extension.')
    
    def validate_file_size(value):
        """ファイルサイズを検証(最大5MB)。"""
        filesize = value.size
        if filesize > 5 * 1024 * 1024:
            raise ValidationError('File too large. Max size is 5MB.')
    
    # models.py
    class Document(models.Model):
        file = models.FileField(
            upload_to='documents/',
            validators=[validate_file_extension, validate_file_size]
        )
    

    安全なファイルストレージ

    # settings.py
    MEDIA_ROOT = '/var/www/media/'
    MEDIA_URL = '/media/'
    
    # 本番環境でメディアに別のドメインを使用
    MEDIA_DOMAIN = 'https://media.example.com'
    
    # ユーザーアップロードを直接提供しない
    # 静的ファイルにはwhitenoiseまたはCDNを使用
    # メディアファイルには別のサーバーまたはS3を使用
    

    APIセキュリティ

    レート制限

    # settings.py
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': [
            'rest_framework.throttling.AnonRateThrottle',
            'rest_framework.throttling.UserRateThrottle'
        ],
        'DEFAULT_THROTTLE_RATES': {
            'anon': '100/day',
            'user': '1000/day',
            'upload': '10/hour',
        }
    }
    
    # カスタムスロットル
    from rest_framework.throttling import UserRateThrottle
    
    class BurstRateThrottle(UserRateThrottle):
        scope = 'burst'
        rate = '60/min'
    
    class SustainedRateThrottle(UserRateThrottle):
        scope = 'sustained'
        rate = '1000/day'
    

    API用認証

    # settings.py
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework.authentication.TokenAuthentication',
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework_simplejwt.authentication.JWTAuthentication',
        ],
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ],
    }
    
    # views.py
    from rest_framework.decorators import api_view, permission_classes
    from rest_framework.permissions import IsAuthenticated
    
    @api_view(['GET', 'POST'])
    @permission_classes([IsAuthenticated])
    def protected_view(request):
        return Response({'message': 'You are authenticated'})
    

    セキュリティヘッダー

    Content Security Policy

    # settings.py
    CSP_DEFAULT_SRC = "'self'"
    CSP_SCRIPT_SRC = "'self' https://cdn.example.com"
    CSP_STYLE_SRC = "'self' 'unsafe-inline'"
    CSP_IMG_SRC = "'self' data: https:"
    CSP_CONNECT_SRC = "'self' https://api.example.com"
    
    # Middleware
    class CSPMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            response = self.get_response(request)
            response['Content-Security-Policy'] = (
                f"default-src {CSP_DEFAULT_SRC}; "
                f"script-src {CSP_SCRIPT_SRC}; "
                f"style-src {CSP_STYLE_SRC}; "
                f"img-src {CSP_IMG_SRC}; "
                f"connect-src {CSP_CONNECT_SRC}"
            )
            return response
    

    環境変数

    シークレットの管理

    # python-decoupleまたはdjango-environを使用
    import environ
    
    env = environ.Env(
        # キャスティング、デフォルト値を設定
        DEBUG=(bool, False)
    )
    
    # .envファイルを読み込む
    environ.Env.read_env()
    
    SECRET_KEY = env('DJANGO_SECRET_KEY')
    DATABASE_URL = env('DATABASE_URL')
    ALLOWED_HOSTS = env.list('ALLOWED_HOSTS')
    
    # .envファイル(これをコミットしない)
    DEBUG=False
    SECRET_KEY=your-secret-key-here
    DATABASE_URL=postgresql://user:password@localhost:5432/dbname
    ALLOWED_HOSTS=example.com,www.example.com
    

    セキュリティイベントのログ記録

    # settings.py
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'file': {
                'level': 'WARNING',
                'class': 'logging.FileHandler',
                'filename': '/var/log/django/security.log',
            },
            'console': {
                'level': 'INFO',
                'class': 'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.security': {
                'handlers': ['file', 'console'],
                'level': 'WARNING',
                'propagate': True,
            },
            'django.request': {
                'handlers': ['file'],
                'level': 'ERROR',
                'propagate': False,
            },
        },
    }
    

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

    チェック説明
    DEBUG = False本番環境でDEBUGを決して実行しない
    HTTPSのみSSLを強制、セキュアクッキー
    強力なシークレットSECRET_KEYに環境変数を使用
    パスワード検証すべてのパスワードバリデータを有効化
    CSRF保護デフォルトで有効、無効にしない
    XSS防止Djangoは自動エスケープ、ユーザー入力で|safeを使用しない
    SQLインジェクションORMを使用、クエリで文字列を連結しない
    ファイルアップロードファイルタイプとサイズを検証
    レート制限APIエンドポイントをスロットル
    セキュリティヘッダーCSP、X-Frame-Options、HSTS
    ログ記録セキュリティイベントをログ
    更新DjangoとDependenciesを最新に保つ

    覚えておいてください: セキュリティは製品ではなく、プロセスです。定期的にセキュリティプラクティスをレビューし、更新してください。

    Alternatives

    Compare before choosing