Communitygithub.com

django-security

Práticas recomendadas de segurança para Django: autenticação, autorização, proteção CSRF, prevenção de SQL Injection, prevenção de XSS e configurações de implantação seguras. Use ao revisar autenticação, autorização, tratamento de entrada ou configurações de implantação do Django.

O que é django-security?

Este skill fornece diretrizes abrangentes de segurança para aplicações Django, abordando vulnerabilidades comuns e melhores práticas. Ele é ativado ao configurar autenticação e autorização, implementar permissões de usuário, revisar problemas de segurança ou implantar aplicações em produção. O conteúdo cobre configurações críticas de produção, como DEBUG=False, cabeçalhos de segurança (HSTS, CSRF, SSL), validação de senhas e gerenciamento de sessões. Também detalha prevenção de SQL Injection usando o ORM do Django com parâmetros, prevenção de XSS com escape de templates e manipulação segura de strings, proteção CSRF embutida, validação de upload de arquivos com verificação de tipo MIME e extensão, segurança de API com limitação de taxa e autenticação (Token, JWT, Session), e controle de acesso baseado em funções (RBAC) com mixins e permissões personalizadas. O skill é compatível com qualquer framework que use Django e fornece exemplos de código Python com configurações de settings.py, views, models e templates, incluindo middleware personalizado para cabeçalhos de segurança.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/django-security

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Práticas Recomendadas de Segurança para Django

Diretrizes abrangentes de segurança para aplicações Django, protegendo contra vulnerabilidades comuns.

Quando Ativar

  • Configurando autenticação e autorização no Django
  • Implementando permissões e funções de usuário
  • Configurando configurações de segurança de produção
  • Revisando aplicações Django para problemas de segurança
  • Implantando aplicações Django em produção

Configurações Principais de Segurança

Configuração de Produção

# settings/production.py
import os

DEBUG = False  # CRÍTICO: Nunca usar True em produção

ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')

# Cabeçalhos de segurança
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000  # 1 ano
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
X_FRAME_OPTIONS = 'DENY'

# HTTPS e Cookies
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SAMESITE = 'Lax'

# Chave secreta (deve ser definida via variável de ambiente)
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
if not SECRET_KEY:
    raise ImproperlyConfigured('A variável de ambiente DJANGO_SECRET_KEY é obrigatória')

# Validação de senha
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',
    },
]

Autenticação

Modelo de Usuário Personalizado

# apps/users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    """Modelo de usuário personalizado para maior segurança."""

    email = models.EmailField(unique=True)
    phone = models.CharField(max_length=20, blank=True)

    USERNAME_FIELD = 'email'  # Usar email como nome de usuário
    REQUIRED_FIELDS = ['username']

    class Meta:
        db_table = 'users'
        verbose_name = 'Usuário'
        verbose_name_plural = 'Usuários'

    def __str__(self):
        return self.email

# settings/base.py
AUTH_USER_MODEL = 'users.User'

Hash de Senha

# Django usa PBKDF2 por padrão. Para maior segurança:
PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
]

Gerenciamento de Sessão

# Configuração de sessão
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # Ou 'db'
SESSION_CACHE_ALIAS = 'default'
SESSION_COOKIE_AGE = 3600 * 24 * 7  # 1 semana
SESSION_SAVE_EVERY_REQUEST = False
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # Melhor UX, mas menos seguro

Autorização

Permissões

# 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', 'Pode publicar posts'),
            ('can_edit_others', 'Pode editar posts de outros'),
        ]

    def user_can_edit(self, user):
        """Verifica se o usuário pode editar este post."""
        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  # Retorna 403 em vez de redirecionar

    def get_queryset(self):
        """Permite que os usuários editem apenas seus próprios posts."""
        return Post.objects.filter(author=self.request.user)

Permissões Personalizadas

# permissions.py
from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
    """Permite que apenas proprietários editem objetos."""

    def has_object_permission(self, request, view, obj):
        # Permissões de leitura permitidas para qualquer requisição
        if request.method in permissions.SAFE_METHODS:
            return True

        # Permissões de escrita apenas para o proprietário
        return obj.author == request.user

class IsAdminOrReadOnly(permissions.BasePermission):
    """Permite que administradores façam tudo, outros apenas leitura."""

    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):
    """Permite apenas usuários verificados."""

    def has_permission(self, request, view):
        return request.user and request.user.is_authenticated and request.user.is_verified

Controle de Acesso Baseado em Funções (RBAC)

# models.py
from django.contrib.auth.models import AbstractUser, Group

class User(AbstractUser):
    ROLE_CHOICES = [
        ('admin', 'Administrador'),
        ('moderator', 'Moderador'),
        ('user', 'Usuário Comum'),
    ]
    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']

# Mixins
class AdminRequiredMixin:
    """Mixin para exigir função de administrador."""

    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)

Prevenção de SQL Injection

Proteção com ORM do Django

# BOM: O ORM do Django escapa parâmetros automaticamente
def get_user(username):
    return User.objects.get(username=username)  # Seguro

# BOM: Usando parâmetros com raw()
def search_users(query):
    return User.objects.raw('SELECT * FROM users WHERE username = %s', [query])

# RUIM: Nunca interpolar entrada do usuário diretamente
def get_user_bad(username):
    return User.objects.raw(f'SELECT * FROM users WHERE username = {username}')  # VULNERÁVEL!

# BOM: Usando filter com escape adequado
def get_users_by_email(email):
    return User.objects.filter(email__iexact=email)  # Seguro

# BOM: Usando objetos Q para consultas complexas
from django.db.models import Q
def search_users_complex(query):
    return User.objects.filter(
        Q(username__icontains=query) |
        Q(email__icontains=query)
    )  # Seguro

Segurança Extra com raw()

# Se precisar usar SQL bruto, sempre use parâmetros
User.objects.raw(
    'SELECT * FROM users WHERE email = %s AND status = %s',
    [user_input_email, status]
)

Prevenção de XSS

Escape de Templates

{# Django escapa variáveis automaticamente por padrão - SEGURO #}
{{ user_input }}  {# HTML escapado #}

{# Marcar explicitamente como seguro apenas para conteúdo confiável #}
{{ trusted_html|safe }}  {# Não escapado #}

{# Usar filtros de template para HTML seguro #}
{{ user_input|escape }}  {# Igual ao padrão #}
{{ user_input|striptags }}  {# Remover todas as tags HTML #}

{# Escape para JavaScript #}
<script>
    var username = {{ username|escapejs }};
</script>

Manipulação Segura de Strings

from django.utils.safestring import mark_safe
from django.utils.html import escape

# RUIM: Nunca marcar entrada do usuário como segura sem escapar
def render_bad(user_input):
    return mark_safe(user_input)  # VULNERÁVEL!

# BOM: Escapar primeiro, depois marcar como seguro
def render_good(user_input):
    return mark_safe(escape(user_input))

# BOM: Usar format_html para HTML com variáveis
from django.utils.html import format_html

def greet_user(username):
    return format_html('<span class="user">{}</span>', escape(username))

Cabeçalhos HTTP

# settings.py
SECURE_CONTENT_TYPE_NOSNIFF = True  # Prevenir sniffing MIME
SECURE_BROWSER_XSS_FILTER = True  # Habilitar filtro XSS
X_FRAME_OPTIONS = 'DENY'  # Prevenir clickjacking

# Middleware personalizado
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

Proteção CSRF

Proteção CSRF Padrão

# settings.py - CSRF está habilitado por padrão
CSRF_COOKIE_SECURE = True  # Enviar apenas por HTTPS
CSRF_COOKIE_HTTPONLY = True  # Impedir acesso via JavaScript
CSRF_COOKIE_SAMESITE = 'Lax'  # Prevenir CSRF em alguns casos
CSRF_TRUSTED_ORIGINS = ['https://example.com']  # Domínios confiáveis

# Uso em template
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Enviar</button>
</form>

# Requisições 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)
});

Isentando Views (Usar com Cuidado)

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt  # Usar apenas quando absolutamente necessário!
def webhook_view(request):
    # Webhook de serviço externo
    pass

Segurança de Upload de Arquivos

Validação de Arquivos

import os
import magic  # pip install python-magic
from django.core.exceptions import ValidationError

ALLOWED_MIMES = {
    'image/jpeg', 'image/png', 'image/gif', 'application/pdf',
}

MIME_TO_EXTENSIONS = {
    'image/jpeg': {'.jpg', '.jpeg'},
    'image/png': {'.png'},
    'image/gif': {'.gif'},
    'application/pdf': {'.pdf'},
}

def validate_file_type(value):
    """Validar tipo de arquivo usando magic bytes e verificar extensão."""
    mime = magic.from_buffer(value.read(2048), mime=True)
    value.seek(0)

    if mime not in ALLOWED_MIMES:
        raise ValidationError('Tipo de arquivo não suportado.')

    ext = os.path.splitext(value.name)[1].lower()
    if ext not in MIME_TO_EXTENSIONS.get(mime, set()):
        raise ValidationError('A extensão do arquivo não corresponde ao conteúdo.')

def validate_file_size(value):
    """Validar tamanho do arquivo (máx. 5MB)."""
    if value.size > 5 * 1024 * 1024:
        raise ValidationError('Arquivo muito grande. O tamanho máximo é 5MB.')

# models.py
class Document(models.Model):
    file = models.FileField(
        upload_to='documents/',
        validators=[validate_file_type, validate_file_size]
    )

Para ambientes onde instalar libmagic é difícil (por exemplo, contêineres mínimos), use o pacote pure-Python filetype como alternativa:

import os
from django.core.exceptions import ValidationError

import filetype  # pip install filetype

ALLOWED_MIMES = {
    'image/jpeg', 'image/png', 'image/gif', 'application/pdf',
}

MIME_TO_EXTENSIONS = {
    'image/jpeg': {'.jpg', '.jpeg'},
    'image/png': {'.png'},
    'image/gif': {'.gif'},
    'application/pdf': {'.pdf'},
}

def validate_file_type(value):
    """Validar tipo de arquivo usando magic bytes."""
    kind = filetype.guess(value.read(2048))
    value.seek(0)

    if kind is None or kind.mime not in ALLOWED_MIMES:
        raise ValidationError('Tipo de arquivo não suportado.')

    ext = os.path.splitext(value.name)[1].lower()
    if ext not in MIME_TO_EXTENSIONS.get(kind.mime, set()):
        raise ValidationError('A extensão do arquivo não corresponde ao conteúdo.')

Armazenamento Seguro de Arquivos

# settings.py
MEDIA_ROOT = '/var/www/media/'
MEDIA_URL = '/media/'

# Usar um domínio separado para mídia em produção
MEDIA_DOMAIN = 'https://media.example.com'

# Não servir uploads de usuário diretamente
# Usar whitenoise ou um CDN para arquivos estáticos
# Usar um servidor separado ou S3 para arquivos de mídia

Segurança de API

Limitação de Taxa

# 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',
    }
}

# Limitação personalizada
from rest_framework.throttling import UserRateThrottle

class BurstRateThrottle(UserRateThrottle):
    scope = 'burst'
    rate = '60/min'

class SustainedRateThrottle(UserRateThrottle):
    scope = 'sustained'
    rate = '1000/day'

Autenticação para APIs

# 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])
# ...

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

Habilidades Relacionadas