[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6D84X2RAVV39V6VDGT9VR16":3,"skill-same:01M6D84X2RAVV39V6VDGT9VR16":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":45,"commitSha":46,"skillDirectory":47,"forksCount":48,"repositoryHtmlUrl":49,"repositoryHomepageUrl":6,"ownerHtmlUrl":50,"ownerBlogUrl":51,"ownerDescription":52,"updatedAt":53,"install":54,"resources":67},"01M6D84X2RAVV39V6VDGT9VR16","django-security",null,"Django security best practices, authentication, authorization, CSRF protection, SQL injection prevention, XSS prevention, and secure deployment configurations.","oabdelmaksoud\u002FSuperClaw","oabdelmaksoud","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F50699149?v=4","01M6D5CVVN778ZCDP1WHS816SP","Omar Abdelmaksoud","01M6D5CW1RHNSKCJR85GJACBFT",2,"MIT","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fdjango-security\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"security","django","django security","sql","secure","deployment","authentication","best practices","security best practices","authorization","injection","xss","prevention","csrf","protection","2026-11-10 10:12:30",false,"---\nname: django-security\ndescription: Django security best practices, authentication, authorization, CSRF protection, SQL injection prevention, XSS prevention, and secure deployment configurations.\norigin: ECC\n---\n\n# Django Security Best Practices\n\nComprehensive security guidelines for Django applications to protect against common vulnerabilities.\n\n## When to Activate\n\n- Setting up Django authentication and authorization\n- Implementing user permissions and roles\n- Configuring production security settings\n- Reviewing Django application for security issues\n- Deploying Django applications to production\n\n## Core Security Settings\n\n### Production Settings Configuration\n\n```python\n# settings\u002Fproduction.py\nimport os\n\nDEBUG = False  # CRITICAL: Never use True in production\n\nALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')\n\n# Security headers\nSECURE_SSL_REDIRECT = True\nSESSION_COOKIE_SECURE = True\nCSRF_COOKIE_SECURE = True\nSECURE_HSTS_SECONDS = 31536000  # 1 year\nSECURE_HSTS_INCLUDE_SUBDOMAINS = True\nSECURE_HSTS_PRELOAD = True\nSECURE_CONTENT_TYPE_NOSNIFF = True\nSECURE_BROWSER_XSS_FILTER = True\nX_FRAME_OPTIONS = 'DENY'\n\n# HTTPS and Cookies\nSESSION_COOKIE_HTTPONLY = True\nCSRF_COOKIE_HTTPONLY = True\nSESSION_COOKIE_SAMESITE = 'Lax'\nCSRF_COOKIE_SAMESITE = 'Lax'\n\n# Secret key (must be set via environment variable)\nSECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')\nif not SECRET_KEY:\n    raise ImproperlyConfigured('DJANGO_SECRET_KEY environment variable is required')\n\n# Password validation\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',\n        'OPTIONS': {\n            'min_length': 12,\n        }\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',\n    },\n]\n```\n\n## Authentication\n\n### Custom User Model\n\n```python\n# apps\u002Fusers\u002Fmodels.py\nfrom django.contrib.auth.models import AbstractUser\nfrom django.db import models\n\nclass User(AbstractUser):\n    \"\"\"Custom user model for better security.\"\"\"\n\n    email = models.EmailField(unique=True)\n    phone = models.CharField(max_length=20, blank=True)\n\n    USERNAME_FIELD = 'email'  # Use email as username\n    REQUIRED_FIELDS = ['username']\n\n    class Meta:\n        db_table = 'users'\n        verbose_name = 'User'\n        verbose_name_plural = 'Users'\n\n    def __str__(self):\n        return self.email\n\n# settings\u002Fbase.py\nAUTH_USER_MODEL = 'users.User'\n```\n\n### Password Hashing\n\n```python\n# Django uses PBKDF2 by default. For stronger security:\nPASSWORD_HASHERS = [\n    'django.contrib.auth.hashers.Argon2PasswordHasher',\n    'django.contrib.auth.hashers.PBKDF2PasswordHasher',\n    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',\n    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',\n]\n```\n\n### Session Management\n\n```python\n# Session configuration\nSESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # Or 'db'\nSESSION_CACHE_ALIAS = 'default'\nSESSION_COOKIE_AGE = 3600 * 24 * 7  # 1 week\nSESSION_SAVE_EVERY_REQUEST = False\nSESSION_EXPIRE_AT_BROWSER_CLOSE = False  # Better UX, but less secure\n```\n\n## Authorization\n\n### Permissions\n\n```python\n# models.py\nfrom django.db import models\nfrom django.contrib.auth.models import Permission\n\nclass Post(models.Model):\n    title = models.CharField(max_length=200)\n    content = models.TextField()\n    author = models.ForeignKey(User, on_delete=models.CASCADE)\n\n    class Meta:\n        permissions = [\n            ('can_publish', 'Can publish posts'),\n            ('can_edit_others', 'Can edit posts of others'),\n        ]\n\n    def user_can_edit(self, user):\n        \"\"\"Check if user can edit this post.\"\"\"\n        return self.author == user or user.has_perm('app.can_edit_others')\n\n# views.py\nfrom django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin\nfrom django.views.generic import UpdateView\n\nclass PostUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):\n    model = Post\n    permission_required = 'app.can_edit_others'\n    raise_exception = True  # Return 403 instead of redirect\n\n    def get_queryset(self):\n        \"\"\"Only allow users to edit their own posts.\"\"\"\n        return Post.objects.filter(author=self.request.user)\n```\n\n### Custom Permissions\n\n```python\n# permissions.py\nfrom rest_framework import permissions\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n    \"\"\"Allow only owners to edit objects.\"\"\"\n\n    def has_object_permission(self, request, view, obj):\n        # Read permissions allowed for any request\n        if request.method in permissions.SAFE_METHODS:\n            return True\n\n        # Write permissions only for owner\n        return obj.author == request.user\n\nclass IsAdminOrReadOnly(permissions.BasePermission):\n    \"\"\"Allow admins to do anything, others read-only.\"\"\"\n\n    def has_permission(self, request, view):\n        if request.method in permissions.SAFE_METHODS:\n            return True\n        return request.user and request.user.is_staff\n\nclass IsVerifiedUser(permissions.BasePermission):\n    \"\"\"Allow only verified users.\"\"\"\n\n    def has_permission(self, request, view):\n        return request.user and request.user.is_authenticated and request.user.is_verified\n```\n\n### Role-Based Access Control (RBAC)\n\n```python\n# models.py\nfrom django.contrib.auth.models import AbstractUser, Group\n\nclass User(AbstractUser):\n    ROLE_CHOICES = [\n        ('admin', 'Administrator'),\n        ('moderator', 'Moderator'),\n        ('user', 'Regular User'),\n    ]\n    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user')\n\n    def is_admin(self):\n        return self.role == 'admin' or self.is_superuser\n\n    def is_moderator(self):\n        return self.role in ['admin', 'moderator']\n\n# Mixins\nclass AdminRequiredMixin:\n    \"\"\"Mixin to require admin role.\"\"\"\n\n    def dispatch(self, request, *args, **kwargs):\n        if not request.user.is_authenticated or not request.user.is_admin():\n            from django.core.exceptions import PermissionDenied\n            raise PermissionDenied\n        return super().dispatch(request, *args, **kwargs)\n```\n\n## SQL Injection Prevention\n\n### Django ORM Protection\n\n```python\n# GOOD: Django ORM automatically escapes parameters\ndef get_user(username):\n    return User.objects.get(username=username)  # Safe\n\n# GOOD: Using parameters with raw()\ndef search_users(query):\n    return User.objects.raw('SELECT * FROM users WHERE username = %s', [query])\n\n# BAD: Never directly interpolate user input\ndef get_user_bad(username):\n    return User.objects.raw(f'SELECT * FROM users WHERE username = {username}')  # VULNERABLE!\n\n# GOOD: Using filter with proper escaping\ndef get_users_by_email(email):\n    return User.objects.filter(email__iexact=email)  # Safe\n\n# GOOD: Using Q objects for complex queries\nfrom django.db.models import Q\ndef search_users_complex(query):\n    return User.objects.filter(\n        Q(username__icontains=query) |\n        Q(email__icontains=query)\n    )  # Safe\n```\n\n### Extra Security with raw()\n\n```python\n# If you must use raw SQL, always use parameters\nUser.objects.raw(\n    'SELECT * FROM users WHERE email = %s AND status = %s',\n    [user_input_email, status]\n)\n```\n\n## XSS Prevention\n\n### Template Escaping\n\n```django\n{# Django auto-escapes variables by default - SAFE #}\n{{ user_input }}  {# Escaped HTML #}\n\n{# Explicitly mark safe only for trusted content #}\n{{ trusted_html|safe }}  {# Not escaped #}\n\n{# Use template filters for safe HTML #}\n{{ user_input|escape }}  {# Same as default #}\n{{ user_input|striptags }}  {# Remove all HTML tags #}\n\n{# JavaScript escaping #}\n\u003Cscript>\n    var username = {{ username|escapejs }};\n\u003C\u002Fscript>\n```\n\n### Safe String Handling\n\n```python\nfrom django.utils.safestring import mark_safe\nfrom django.utils.html import escape\n\n# BAD: Never mark user input as safe without escaping\ndef render_bad(user_input):\n    return mark_safe(user_input)  # VULNERABLE!\n\n# GOOD: Escape first, then mark safe\ndef render_good(user_input):\n    return mark_safe(escape(user_input))\n\n# GOOD: Use format_html for HTML with variables\nfrom django.utils.html import format_html\n\ndef greet_user(username):\n    return format_html('\u003Cspan class=\"user\">{}\u003C\u002Fspan>', escape(username))\n```\n\n### HTTP Headers\n\n```python\n# settings.py\nSECURE_CONTENT_TYPE_NOSNIFF = True  # Prevent MIME sniffing\nSECURE_BROWSER_XSS_FILTER = True  # Enable XSS filter\nX_FRAME_OPTIONS = 'DENY'  # Prevent clickjacking\n\n# Custom middleware\nfrom django.conf import settings\n\nclass SecurityHeaderMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        response = self.get_response(request)\n        response['X-Content-Type-Options'] = 'nosniff'\n        response['X-Frame-Options'] = 'DENY'\n        response['X-XSS-Protection'] = '1; mode=block'\n        response['Content-Security-Policy'] = \"default-src 'self'\"\n        return response\n```\n\n## CSRF Protection\n\n### Default CSRF Protection\n\n```python\n# settings.py - CSRF is enabled by default\nCSRF_COOKIE_SECURE = True  # Only send over HTTPS\nCSRF_COOKIE_HTTPONLY = True  # Prevent JavaScript access\nCSRF_COOKIE_SAMESITE = 'Lax'  # Prevent CSRF in some cases\nCSRF_TRUSTED_ORIGINS = ['https:\u002F\u002Fexample.com']  # Trusted domains\n\n# Template usage\n\u003Cform method=\"post\">\n    {% csrf_token %}\n    {{ form.as_p }}\n    \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n\u003C\u002Fform>\n\n# AJAX requests\nfunction getCookie(name) {\n    let cookieValue = null;\n    if (document.cookie && document.cookie !== '') {\n        const cookies = document.cookie.split(';');\n        for (let i = 0; i \u003C cookies.length; i++) {\n            const cookie = cookies[i].trim();\n            if (cookie.substring(0, name.length + 1) === (name + '=')) {\n                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n                break;\n            }\n        }\n    }\n    return cookieValue;\n}\n\nfetch('\u002Fapi\u002Fendpoint\u002F', {\n    method: 'POST',\n    headers: {\n        'X-CSRFToken': getCookie('csrftoken'),\n        'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify(data)\n});\n```\n\n### Exempting Views (Use Carefully)\n\n```python\nfrom django.views.decorators.csrf import csrf_exempt\n\n@csrf_exempt  # Only use when absolutely necessary!\ndef webhook_view(request):\n    # Webhook from external service\n    pass\n```\n\n## File Upload Security\n\n### File Validation\n\n```python\nimport os\nfrom django.core.exceptions import ValidationError\n\ndef validate_file_extension(value):\n    \"\"\"Validate file extension.\"\"\"\n    ext = os.path.splitext(value.name)[1]\n    valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.pdf']\n    if not ext.lower() in valid_extensions:\n        raise ValidationError('Unsupported file extension.')\n\ndef validate_file_size(value):\n    \"\"\"Validate file size (max 5MB).\"\"\"\n    filesize = value.size\n    if filesize > 5 * 1024 * 1024:\n        raise ValidationError('File too large. Max size is 5MB.')\n\n# models.py\nclass Document(models.Model):\n    file = models.FileField(\n        upload_to='documents\u002F',\n        validators=[validate_file_extension, validate_file_size]\n    )\n```\n\n### Secure File Storage\n\n```python\n# settings.py\nMEDIA_ROOT = '\u002Fvar\u002Fwww\u002Fmedia\u002F'\nMEDIA_URL = '\u002Fmedia\u002F'\n\n# Use a separate domain for media in production\nMEDIA_DOMAIN = 'https:\u002F\u002Fmedia.example.com'\n\n# Don't serve user uploads directly\n# Use whitenoise or a CDN for static files\n# Use a separate server or S3 for media files\n```\n\n## API Security\n\n### Rate Limiting\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    'DEFAULT_THROTTLE_CLASSES': [\n        'rest_framework.throttling.AnonRateThrottle',\n        'rest_framework.throttling.UserRateThrottle'\n    ],\n    'DEFAULT_THROTTLE_RATES': {\n        'anon': '100\u002Fday',\n        'user': '1000\u002Fday',\n        'upload': '10\u002Fhour',\n    }\n}\n\n# Custom throttle\nfrom rest_framework.throttling import UserRateThrottle\n\nclass BurstRateThrottle(UserRateThrottle):\n    scope = 'burst'\n    rate = '60\u002Fmin'\n\nclass SustainedRateThrottle(UserRateThrottle):\n    scope = 'sustained'\n    rate = '1000\u002Fday'\n```\n\n### Authentication for APIs\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    'DEFAULT_AUTHENTICATION_CLASSES': [\n        'rest_framework.authentication.TokenAuthentication',\n        'rest_framework.authentication.SessionAuthentication',\n        'rest_framework_simplejwt.authentication.JWTAuthentication',\n    ],\n    'DEFAULT_PERMISSION_CLASSES': [\n        'rest_framework.permissions.IsAuthenticated',\n    ],\n}\n\n# views.py\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\n\n@api_view(['GET', 'POST'])\n@permission_classes([IsAuthenticated])\ndef protected_view(request):\n    return Response({'message': 'You are authenticated'})\n```\n\n## Security Headers\n\n### Content Security Policy\n\n```python\n# settings.py\nCSP_DEFAULT_SRC = \"'self'\"\nCSP_SCRIPT_SRC = \"'self' https:\u002F\u002Fcdn.example.com\"\nCSP_STYLE_SRC = \"'self' 'unsafe-inline'\"\nCSP_IMG_SRC = \"'self' data: https:\"\nCSP_CONNECT_SRC = \"'self' https:\u002F\u002Fapi.example.com\"\n\n# Middleware\nclass CSPMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        response = self.get_response(request)\n        response['Content-Security-Policy'] = (\n            f\"default-src {CSP_DEFAULT_SRC}; \"\n            f\"script-src {CSP_SCRIPT_SRC}; \"\n            f\"style-src {CSP_STYLE_SRC}; \"\n            f\"img-src {CSP_IMG_SRC}; \"\n            f\"connect-src {CSP_CONNECT_SRC}\"\n        )\n        return response\n```\n\n## Environment Variables\n\n### Managing Secrets\n\n```python\n# Use python-decouple or django-environ\nimport environ\n\nenv = environ.Env(\n    # set casting, default value\n    DEBUG=(bool, False)\n)\n\n# reading .env file\nenviron.Env.read_env()\n\nSECRET_KEY = env('DJANGO_SECRET_KEY')\nDATABASE_URL = env('DATABASE_URL')\nALLOWED_HOSTS = env.list('ALLOWED_HOSTS')\n\n# .env file (never commit this)\nDEBUG=False\nSECRET_KEY=your-secret-key-here\nDATABASE_URL=postgresql:\u002F\u002Fuser:password@localhost:5432\u002Fdbname\nALLOWED_HOSTS=example.com,www.example.com\n```\n\n## Logging Security Events\n\n```python\n# settings.py\nLOGGING = {\n    'version': 1,\n    'disable_existing_loggers': False,\n    'handlers': {\n        'file': {\n            'level': 'WARNING',\n            'class': 'logging.FileHandler',\n            'filename': '\u002Fvar\u002Flog\u002Fdjango\u002Fsecurity.log',\n        },\n        'console': {\n            'level': 'INFO',\n            'class': 'logging.StreamHandler',\n        },\n    },\n    'loggers': {\n        'django.security': {\n            'handlers': ['file', 'console'],\n            'level': 'WARNING',\n            'propagate': True,\n        },\n        'django.request': {\n            'handlers': ['file'],\n            'level': 'ERROR',\n            'propagate': False,\n        },\n    },\n}\n```\n\n## Quick Security Checklist\n\n| Check | Description |\n|-------|-------------|\n| `DEBUG = False` | Never run with DEBUG in production |\n| HTTPS only | Force SSL, secure cookies |\n| Strong secrets | Use environment variables for SECRET_KEY |\n| Password validation | Enable all password validators |\n| CSRF protection | Enabled by default, don't disable |\n| XSS prevention | Django auto-escapes, don't use `&#124;safe` with user input |\n| SQL injection | Use ORM, never concatenate strings in queries |\n| File uploads | Validate file type and size |\n| Rate limiting | Throttle API endpoints |\n| Security headers | CSP, X-Frame-Options, HSTS |\n| Logging | Log security events |\n| Updates | Keep Django and dependencies updated |\n\nRemember: Security is a process, not a product. Regularly review and update your security practices.\n","# Django Security Best Practices\n\nComprehensive security guidelines for Django applications to protect against common vulnerabilities.\n\n## When to Activate\n\n- Setting up Django authentication and authorization\n- Implementing user permissions and roles\n- Configuring production security settings\n- Reviewing Django application for security issues\n- Deploying Django applications to production\n\n## Core Security Settings\n\n### Production Settings Configuration\n\n```python\n# settings\u002Fproduction.py\nimport os\n\nDEBUG = False  # CRITICAL: Never use True in production\n\nALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')\n\n# Security headers\nSECURE_SSL_REDIRECT = True\nSESSION_COOKIE_SECURE = True\nCSRF_COOKIE_SECURE = True\nSECURE_HSTS_SECONDS = 31536000  # 1 year\nSECURE_HSTS_INCLUDE_SUBDOMAINS = True\nSECURE_HSTS_PRELOAD = True\nSECURE_CONTENT_TYPE_NOSNIFF = True\nSECURE_BROWSER_XSS_FILTER = True\nX_FRAME_OPTIONS = 'DENY'\n\n# HTTPS and Cookies\nSESSION_COOKIE_HTTPONLY = True\nCSRF_COOKIE_HTTPONLY = True\nSESSION_COOKIE_SAMESITE = 'Lax'\nCSRF_COOKIE_SAMESITE = 'Lax'\n\n# Secret key (must be set via environment variable)\nSECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')\nif not SECRET_KEY:\n    raise ImproperlyConfigured('DJANGO_SECRET_KEY environment variable is required')\n\n# Password validation\nAUTH_PASSWORD_VALIDATORS = [\n    {\n        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',\n        'OPTIONS': {\n            'min_length': 12,\n        }\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',\n    },\n    {\n        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',\n    },\n]\n```\n\n## Authentication\n\n### Custom User Model\n\n```python\n# apps\u002Fusers\u002Fmodels.py\nfrom django.contrib.auth.models import AbstractUser\nfrom django.db import models\n\nclass User(AbstractUser):\n    \"\"\"Custom user model for better security.\"\"\"\n\n    email = models.EmailField(unique=True)\n    phone = models.CharField(max_length=20, blank=True)\n\n    USERNAME_FIELD = 'email'  # Use email as username\n    REQUIRED_FIELDS = ['username']\n\n    class Meta:\n        db_table = 'users'\n        verbose_name = 'User'\n        verbose_name_plural = 'Users'\n\n    def __str__(self):\n        return self.email\n\n# settings\u002Fbase.py\nAUTH_USER_MODEL = 'users.User'\n```\n\n### Password Hashing\n\n```python\n# Django uses PBKDF2 by default. For stronger security:\nPASSWORD_HASHERS = [\n    'django.contrib.auth.hashers.Argon2PasswordHasher',\n    'django.contrib.auth.hashers.PBKDF2PasswordHasher',\n    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',\n    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',\n]\n```\n\n### Session Management\n\n```python\n# Session configuration\nSESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # Or 'db'\nSESSION_CACHE_ALIAS = 'default'\nSESSION_COOKIE_AGE = 3600 * 24 * 7  # 1 week\nSESSION_SAVE_EVERY_REQUEST = False\nSESSION_EXPIRE_AT_BROWSER_CLOSE = False  # Better UX, but less secure\n```\n\n## Authorization\n\n### Permissions\n\n```python\n# models.py\nfrom django.db import models\nfrom django.contrib.auth.models import Permission\n\nclass Post(models.Model):\n    title = models.CharField(max_length=200)\n    content = models.TextField()\n    author = models.ForeignKey(User, on_delete=models.CASCADE)\n\n    class Meta:\n        permissions = [\n            ('can_publish', 'Can publish posts'),\n            ('can_edit_others', 'Can edit posts of others'),\n        ]\n\n    def user_can_edit(self, user):\n        \"\"\"Check if user can edit this post.\"\"\"\n        return self.author == user or user.has_perm('app.can_edit_others')\n\n# views.py\nfrom django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin\nfrom django.views.generic import UpdateView\n\nclass PostUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):\n    model = Post\n    permission_required = 'app.can_edit_others'\n    raise_exception = True  # Return 403 instead of redirect\n\n    def get_queryset(self):\n        \"\"\"Only allow users to edit their own posts.\"\"\"\n        return Post.objects.filter(author=self.request.user)\n```\n\n### Custom Permissions\n\n```python\n# permissions.py\nfrom rest_framework import permissions\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n    \"\"\"Allow only owners to edit objects.\"\"\"\n\n    def has_object_permission(self, request, view, obj):\n        # Read permissions allowed for any request\n        if request.method in permissions.SAFE_METHODS:\n            return True\n\n        # Write permissions only for owner\n        return obj.author == request.user\n\nclass IsAdminOrReadOnly(permissions.BasePermission):\n    \"\"\"Allow admins to do anything, others read-only.\"\"\"\n\n    def has_permission(self, request, view):\n        if request.method in permissions.SAFE_METHODS:\n            return True\n        return request.user and request.user.is_staff\n\nclass IsVerifiedUser(permissions.BasePermission):\n    \"\"\"Allow only verified users.\"\"\"\n\n    def has_permission(self, request, view):\n        return request.user and request.user.is_authenticated and request.user.is_verified\n```\n\n### Role-Based Access Control (RBAC)\n\n```python\n# models.py\nfrom django.contrib.auth.models import AbstractUser, Group\n\nclass User(AbstractUser):\n    ROLE_CHOICES = [\n        ('admin', 'Administrator'),\n        ('moderator', 'Moderator'),\n        ('user', 'Regular User'),\n    ]\n    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user')\n\n    def is_admin(self):\n        return self.role == 'admin' or self.is_superuser\n\n    def is_moderator(self):\n        return self.role in ['admin', 'moderator']\n\n# Mixins\nclass AdminRequiredMixin:\n    \"\"\"Mixin to require admin role.\"\"\"\n\n    def dispatch(self, request, *args, **kwargs):\n        if not request.user.is_authenticated or not request.user.is_admin():\n            from django.core.exceptions import PermissionDenied\n            raise PermissionDenied\n        return super().dispatch(request, *args, **kwargs)\n```\n\n## SQL Injection Prevention\n\n### Django ORM Protection\n\n```python\n# GOOD: Django ORM automatically escapes parameters\ndef get_user(username):\n    return User.objects.get(username=username)  # Safe\n\n# GOOD: Using parameters with raw()\ndef search_users(query):\n    return User.objects.raw('SELECT * FROM users WHERE username = %s', [query])\n\n# BAD: Never directly interpolate user input\ndef get_user_bad(username):\n    return User.objects.raw(f'SELECT * FROM users WHERE username = {username}')  # VULNERABLE!\n\n# GOOD: Using filter with proper escaping\ndef get_users_by_email(email):\n    return User.objects.filter(email__iexact=email)  # Safe\n\n# GOOD: Using Q objects for complex queries\nfrom django.db.models import Q\ndef search_users_complex(query):\n    return User.objects.filter(\n        Q(username__icontains=query) |\n        Q(email__icontains=query)\n    )  # Safe\n```\n\n### Extra Security with raw()\n\n```python\n# If you must use raw SQL, always use parameters\nUser.objects.raw(\n    'SELECT * FROM users WHERE email = %s AND status = %s',\n    [user_input_email, status]\n)\n```\n\n## XSS Prevention\n\n### Template Escaping\n\n```django\n{# Django auto-escapes variables by default - SAFE #}\n{{ user_input }}  {# Escaped HTML #}\n\n{# Explicitly mark safe only for trusted content #}\n{{ trusted_html|safe }}  {# Not escaped #}\n\n{# Use template filters for safe HTML #}\n{{ user_input|escape }}  {# Same as default #}\n{{ user_input|striptags }}  {# Remove all HTML tags #}\n\n{# JavaScript escaping #}\n\u003Cscript>\n    var username = {{ username|escapejs }};\n\u003C\u002Fscript>\n```\n\n### Safe String Handling\n\n```python\nfrom django.utils.safestring import mark_safe\nfrom django.utils.html import escape\n\n# BAD: Never mark user input as safe without escaping\ndef render_bad(user_input):\n    return mark_safe(user_input)  # VULNERABLE!\n\n# GOOD: Escape first, then mark safe\ndef render_good(user_input):\n    return mark_safe(escape(user_input))\n\n# GOOD: Use format_html for HTML with variables\nfrom django.utils.html import format_html\n\ndef greet_user(username):\n    return format_html('\u003Cspan class=\"user\">{}\u003C\u002Fspan>', escape(username))\n```\n\n### HTTP Headers\n\n```python\n# settings.py\nSECURE_CONTENT_TYPE_NOSNIFF = True  # Prevent MIME sniffing\nSECURE_BROWSER_XSS_FILTER = True  # Enable XSS filter\nX_FRAME_OPTIONS = 'DENY'  # Prevent clickjacking\n\n# Custom middleware\nfrom django.conf import settings\n\nclass SecurityHeaderMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        response = self.get_response(request)\n        response['X-Content-Type-Options'] = 'nosniff'\n        response['X-Frame-Options'] = 'DENY'\n        response['X-XSS-Protection'] = '1; mode=block'\n        response['Content-Security-Policy'] = \"default-src 'self'\"\n        return response\n```\n\n## CSRF Protection\n\n### Default CSRF Protection\n\n```python\n# settings.py - CSRF is enabled by default\nCSRF_COOKIE_SECURE = True  # Only send over HTTPS\nCSRF_COOKIE_HTTPONLY = True  # Prevent JavaScript access\nCSRF_COOKIE_SAMESITE = 'Lax'  # Prevent CSRF in some cases\nCSRF_TRUSTED_ORIGINS = ['https:\u002F\u002Fexample.com']  # Trusted domains\n\n# Template usage\n\u003Cform method=\"post\">\n    {% csrf_token %}\n    {{ form.as_p }}\n    \u003Cbutton type=\"submit\">Submit\u003C\u002Fbutton>\n\u003C\u002Fform>\n\n# AJAX requests\nfunction getCookie(name) {\n    let cookieValue = null;\n    if (document.cookie && document.cookie !== '') {\n        const cookies = document.cookie.split(';');\n        for (let i = 0; i \u003C cookies.length; i++) {\n            const cookie = cookies[i].trim();\n            if (cookie.substring(0, name.length + 1) === (name + '=')) {\n                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n                break;\n            }\n        }\n    }\n    return cookieValue;\n}\n\nfetch('\u002Fapi\u002Fendpoint\u002F', {\n    method: 'POST',\n    headers: {\n        'X-CSRFToken': getCookie('csrftoken'),\n        'Content-Type': 'application\u002Fjson',\n    },\n    body: JSON.stringify(data)\n});\n```\n\n### Exempting Views (Use Carefully)\n\n```python\nfrom django.views.decorators.csrf import csrf_exempt\n\n@csrf_exempt  # Only use when absolutely necessary!\ndef webhook_view(request):\n    # Webhook from external service\n    pass\n```\n\n## File Upload Security\n\n### File Validation\n\n```python\nimport os\nfrom django.core.exceptions import ValidationError\n\ndef validate_file_extension(value):\n    \"\"\"Validate file extension.\"\"\"\n    ext = os.path.splitext(value.name)[1]\n    valid_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.pdf']\n    if not ext.lower() in valid_extensions:\n        raise ValidationError('Unsupported file extension.')\n\ndef validate_file_size(value):\n    \"\"\"Validate file size (max 5MB).\"\"\"\n    filesize = value.size\n    if filesize > 5 * 1024 * 1024:\n        raise ValidationError('File too large. Max size is 5MB.')\n\n# models.py\nclass Document(models.Model):\n    file = models.FileField(\n        upload_to='documents\u002F',\n        validators=[validate_file_extension, validate_file_size]\n    )\n```\n\n### Secure File Storage\n\n```python\n# settings.py\nMEDIA_ROOT = '\u002Fvar\u002Fwww\u002Fmedia\u002F'\nMEDIA_URL = '\u002Fmedia\u002F'\n\n# Use a separate domain for media in production\nMEDIA_DOMAIN = 'https:\u002F\u002Fmedia.example.com'\n\n# Don't serve user uploads directly\n# Use whitenoise or a CDN for static files\n# Use a separate server or S3 for media files\n```\n\n## API Security\n\n### Rate Limiting\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    'DEFAULT_THROTTLE_CLASSES': [\n        'rest_framework.throttling.AnonRateThrottle',\n        'rest_framework.throttling.UserRateThrottle'\n    ],\n    'DEFAULT_THROTTLE_RATES': {\n        'anon': '100\u002Fday',\n        'user': '1000\u002Fday',\n        'upload': '10\u002Fhour',\n    }\n}\n\n# Custom throttle\nfrom rest_framework.throttling import UserRateThrottle\n\nclass BurstRateThrottle(UserRateThrottle):\n    scope = 'burst'\n    rate = '60\u002Fmin'\n\nclass SustainedRateThrottle(UserRateThrottle):\n    scope = 'sustained'\n    rate = '1000\u002Fday'\n```\n\n### Authentication for APIs\n\n```python\n# settings.py\nREST_FRAMEWORK = {\n    'DEFAULT_AUTHENTICATION_CLASSES': [\n        'rest_framework.authentication.TokenAuthentication',\n        'rest_framework.authentication.SessionAuthentication',\n        'rest_framework_simplejwt.authentication.JWTAuthentication',\n    ],\n    'DEFAULT_PERMISSION_CLASSES': [\n        'rest_framework.permissions.IsAuthenticated',\n    ],\n}\n\n# views.py\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\n\n@api_view(['GET', 'POST'])\n@permission_classes([IsAuthenticated])\ndef protected_view(request):\n    return Response({'message': 'You are authenticated'})\n```\n\n## Security Headers\n\n### Content Security Policy\n\n```python\n# settings.py\nCSP_DEFAULT_SRC = \"'self'\"\nCSP_SCRIPT_SRC = \"'self' https:\u002F\u002Fcdn.example.com\"\nCSP_STYLE_SRC = \"'self' 'unsafe-inline'\"\nCSP_IMG_SRC = \"'self' data: https:\"\nCSP_CONNECT_SRC = \"'self' https:\u002F\u002Fapi.example.com\"\n\n# Middleware\nclass CSPMiddleware:\n    def __init__(self, get_response):\n        self.get_response = get_response\n\n    def __call__(self, request):\n        response = self.get_response(request)\n        response['Content-Security-Policy'] = (\n            f\"default-src {CSP_DEFAULT_SRC}; \"\n            f\"script-src {CSP_SCRIPT_SRC}; \"\n            f\"style-src {CSP_STYLE_SRC}; \"\n            f\"img-src {CSP_IMG_SRC}; \"\n            f\"connect-src {CSP_CONNECT_SRC}\"\n        )\n        return response\n```\n\n## Environment Variables\n\n### Managing Secrets\n\n```python\n# Use python-decouple or django-environ\nimport environ\n\nenv = environ.Env(\n    # set casting, default value\n    DEBUG=(bool, False)\n)\n\n# reading .env file\nenviron.Env.read_env()\n\nSECRET_KEY = env('DJANGO_SECRET_KEY')\nDATABASE_URL = env('DATABASE_URL')\nALLOWED_HOSTS = env.list('ALLOWED_HOSTS')\n\n# .env file (never commit this)\nDEBUG=False\nSECRET_KEY=your-secret-key-here\nDATABASE_URL=postgresql:\u002F\u002Fuser:password@localhost:5432\u002Fdbname\nALLOWED_HOSTS=example.com,www.example.com\n```\n\n## Logging Security Events\n\n```python\n# settings.py\nLOGGING = {\n    'version': 1,\n    'disable_existing_loggers': False,\n    'handlers': {\n        'file': {\n            'level': 'WARNING',\n            'class': 'logging.FileHandler',\n            'filename': '\u002Fvar\u002Flog\u002Fdjango\u002Fsecurity.log',\n        },\n        'console': {\n            'level': 'INFO',\n            'class': 'logging.StreamHandler',\n        },\n    },\n    'loggers': {\n        'django.security': {\n            'handlers': ['file', 'console'],\n            'level': 'WARNING',\n            'propagate': True,\n        },\n        'django.request': {\n            'handlers': ['file'],\n            'level': 'ERROR',\n            'propagate': False,\n        },\n    },\n}\n```\n\n## Quick Security Checklist\n\n| Check | Description |\n|-------|-------------|\n| `DEBUG = False` | Never run with DEBUG in production |\n| HTTPS only | Force SSL, secure cookies |\n| Strong secrets | Use environment variables for SECRET_KEY |\n| Password validation | Enable all password validators |\n| CSRF protection | Enabled by default, don't disable |\n| XSS prevention | Django auto-escapes, don't use `&#124;safe` with user input |\n| SQL injection | Use ORM, never concatenate strings in queries |\n| File uploads | Validate file type and size |\n| Rate limiting | Throttle API endpoints |\n| Security headers | CSP, X-Frame-Options, HSTS |\n| Logging | Log security events |\n| Updates | Keep Django and dependencies updated |\n\nRemember: Security is a process, not a product. Regularly review and update your security practices.\n",{"name":5,"origin":44,"description":7},"ECC","main","7b610356e36623652299fa2acb477ff821b1d920","upstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fdjango-security",0,"https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fo-abdelmaksoud\u002F","Full-Stack Engineer | AI Systems Architect | Building autonomous multi-agent systems","2026-03-08 21:12:53",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add oabdelmaksoud\u002FSuperClaw --skill django-security",{"tool":60,"command":61},"bunx","bunx skills add oabdelmaksoud\u002FSuperClaw --skill django-security",{"tool":63,"command":64},"pnpm","pnpm dlx skills add oabdelmaksoud\u002FSuperClaw --skill django-security","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fdjango-security\u002FSKILL.md",true,[68],{"path":69,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":72,"sourceHtmlUrl":73},"bmad-skill-manifest.yaml","REFERENCE","参考文档",922,"https:\u002F\u002Fgithub.com\u002FCanVc\u002Fdoc-chat\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fbmad-agent-architect\u002Fbmad-skill-manifest.yaml",[75,94,108,139,164,182],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":84,"publishedAt":39},"01M6D88QCPTBZVCRED0NZ1Y8K8","visa-doc-translate","Translate visa application documents (images) to English and create a bilingual PDF with original and translation","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fvisa-doc-translate\u002FSKILL.md",[81],{"categoryNo":82,"categoryName":83,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000002","文档处理",[85,86,87,88,89,90,91,92,93],"translate","doc","visa doc translate","translation","application","create","images","PDF","documents",{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":39},"01M6D88NBM95T3TFM50CYYAP65","verification-loop","A comprehensive verification system for Claude Code sessions.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[101,102,103,104,105,106,107],"verification","loop","verification loop","sessions","code","claude code sessions","system",{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":125,"publishedAt":39},"01M6D88JFZ2P996GVRHJNSZSTM","tdd-workflow","Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Ftdd-workflow\u002FSKILL.md",[114,117,120],{"categoryNo":115,"categoryName":116,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":118,"categoryName":119,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":121,"categoryName":122,"taxonomyType":123,"taxonomyTypeDesc":124},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[126,127,128,129,130,131,105,132,133,134,135,136,137,138],"tdd","workflow","tdd workflow","e2e tests","e2e","integration","development","use","test","refactoring","coverage","tests","writing",{"skillNo":140,"name":141,"nameZh":6,"description":142,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":143,"categories":144,"keywords":145,"publishedAt":39},"01M6D88FTHRRSVJMXF2G7MQAK3","swiftui-patterns","SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS\u002FmacOS UI best practices.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswiftui-patterns\u002FSKILL.md",[],[146,147,148,149,150,151,152,31,153,154,155,156,157,158,159,160,161,162,163],"patterns","swiftui","swiftui patterns","architecture","macos","performance","state management","state","ui","Optimization","ios","architecture patterns","Composition","performance optimization","view","management","swiftui architecture","navigation",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":171,"publishedAt":39},"01M6D88D527QTQT9DKHTRFN6EA","swift-protocol-di-testing","Protocol-based dependency injection for testable Swift code — mock file system, network, and external APIs using focused protocols and Swift Testing.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-protocol-di-testing\u002FSKILL.md",[170],{"categoryNo":115,"categoryName":116,"taxonomyType":21,"taxonomyTypeDesc":22},[172,173,174,175,105,176,177,178,34,107,179,180,181],"swift protocol di testing","protocol","swift","testing","protocols","file","network","dependency","swift testing","dependency injection",{"skillNo":183,"name":184,"nameZh":6,"description":185,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":186,"categories":187,"keywords":188,"publishedAt":39},"01M6D88AJW8H2QNWSW5ZY82R43","swift-concurrency-6-2","Swift 6.2 Approachable Concurrency — single-threaded by default, @concurrent for explicit background offloading, isolated conformances for main actor types.","https:\u002F\u002Fgithub.com\u002Foabdelmaksoud\u002FSuperClaw\u002Fblob\u002Fmain\u002Fupstream-sync\u002Fwork\u002Fecc\u002Fskills\u002Fswift-concurrency-6-2\u002FSKILL.md",[],[189,190,174,191,192,45],"concurrency","swift concurrency","swift concurrency 6 2","default"]