Como usar a proteção CSRF do Django

Para aproveitar das vantagens da proteção CSRF nas suas views, siga estes passos:

  1. O middleware CSRF está ativado por padrão na configuração MIDDLEWARE. Se você sobrescrever esta configuração, lembre-se que 'django.middleware.csrf.CsrfViewMiddleware' deve vir antes do que qualquer middleware de view que assuma que ataques CSRF já tenham sido resolvidos.

    Se você o desabilitou, o que não é recomendado, você pode usar csrf_protect() em views especifícas que você deseja proteger (veja abaixo).

  2. Em qualquer template que usa um formulário POST, use a tag csrf_token dentro do 1 elemento se o formulário é para uma URL interna, por exemplo:

    <form method="post">{% csrf_token %}
    

    Isso não deve feito para formulários POST para URLs externas, já que isso causaria o vazamento do token CSRF, levando a uma vulnerabilidade.

  3. Nas devidas funções de view, garanta que RequestContext é utilizado para renderizar a resposta, assim {% csrf_token %} irá funcionar como o esperado. Se você está usando a função render(), views genéricas, ou apps contrib, você não precisa fazer isso, já que todas essas já fazem uso do RequestContext.

Usando a proteção CSRF com AJAX

Mesmo que o método acima possa ser utilizado para requisições POST AJAX, existem algumas incoveniências: você precisa se lembrar de passar o token CSRF nos dados de POST em todas as requisições POST. Por esse motivo existe um método alternativo: Em cada XMLHttpRequest, defina um cabeçalho customizado X-CSRFToken (como especificado pela configuração CSRF_HEADER_NAME) com o valor do token CSRF. Isso geralmente é mais fácil por que muitos frameworks Javascript dão hooks que permitem que cabeçalhos sejam definidos em toda requisição.

Primeiro, você precisa pegar o token CSRF. Como fazer isso depende das configurações CSRF_USE_SESSIONS e CSRF_COOKIE_HTTPONLY estarem habilitadas.

Definindo o token em uma requisição AJAX

Finalmente, você precisará definir o cabeçalho na sua requisição AJAX. Using a API fetch():

const request = new Request(
    /* URL */,
    {
        method: 'POST',
        headers: {'X-CSRFToken': csrftoken},
        mode: 'same-origin' // Do not send CSRF token to another domain.
    }
);
fetch(request).then(function(response) {
    // ...
});

Usando a proteção CSRF em templates Jinja2

O backend de template Jinja2 do Django adiciona {{ csrf_input }} para o contexto de todos os templates que é equivalente ao {% csrf_token %} na linguagem de template do Django. Por exemplo:

<form method="post">{{ csrf_input }}

Usando o decorador de método

Em vez de adicionar CsrfViewMiddleware como uma proteção geral, você pode usar o decorador csrf_protect(), que tem exatamente a mesma funcionalidade, em views específicas que precisem de proteção. É necessário usá-lo tanto nas views que inserem o token CSRF na sua saída, quanto aquelas que aceitem dados de um formulário POST. (Geralmente essas duas estão na mesma função de view, mas não necessariamente).

O uso apenas do decorador não é recomendado, já que se você se esquecer de usá-lo, você pode ter uma brecha de segurança. A estratégia de usar ‘Cinto e suspensório’ é aceitável, e traz consequências mínimas.

Lidando com requisições rejeitadas

Por padrão, uma resposta ‘403 Proibido’ é enviada para o usuário caso a requisição recebida falhe nas verificações feitas pelo CsrfViewMiddleware. Geralmente isso é apenas visto quando realmente há um Cross Site Request Forgery, ou quando devido um erro de programação, o token CSRF não é incluído junto do formulário POST.

A página de erro, porém, não é muito amigável, então você pode definir sua própria view para lidar com esta condição. Para fazer isso, defina a configuração CSRF_FAILURE_VIEW.

Falhas CSRF são logadas como aviso pelo logger django.security.csrf.

Usando a proteção CSRF com cacheamento

Se a tag de template csrf_token é usado por um template (ou a função get_token é chamada de um outro jeito), o CsrfViewMiddleware adicionará o cookie e um cabeçalho Vary: Cookie para a resposta. Isso significa que o middleware irá funcionar com o middleware de cachê se usado conforme instruído (UpdateCacheMiddleware deve vir antes de qualquer outro middleware).

Porém, se você usar decoradores de cachê em views individuais, o middleware de CSRF não será capaz de definir o cabeçalho Vary ou o cookie CSRF, e a resposta será cacheada sem nenhum deles. Nesse caso, quaisquer views que precisem que um token CSRF seja inserido você deve usar o decorador django.views.decorators.csrf.csrf_protect() primeiro:

from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect


@cache_page(60 * 15)
@csrf_protect
def my_view(request): ...

Se você está usando class-based views, você pode se referir à Decorating class-based views.

Testes e a proteção CSRF

O CsrfViewMiddleware normalmente será um grande obstáculo para testar as funções view, devido a necessidade do token CSRF estar presente em toda requisição POST. Por isso, o cliente HTTP de testes do Django foi modificado para definir uma flag nas requisições que relaxam o middleware e o decorador csrf_protect para que eles não rejeitem as requisições. Em todos outros casos (por exemplo enviando cookies etc.), eles se comportam da mesma maneira.

Se, por algum motivo, você quer que o cliente de teste realize as verificações CSRF, você pode criar uma instância do cliente de teste que força as verificações CSRF:

>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)

Casos extremos

Algumas views podem ter requisitos incomuns que não se encaixam nos padrões demonstrados aqui. Algumas ferramentas podem ser úteis nessas situações. Os cenários em que elas podem ser necessárias estão descritos nesta seção.

Desabilitando a proteção CSRF para apenas algumas views

A maioria das views precisam de proteção CSRF, mas algumas não.

Solução: Em vez de desabilitar o middleware e aplicar csrf_protect para todas as views que precisam, habilite o middleware e use csrf_exempt().

Definindo o token quando CsrfViewMiddleware.process_view() não é utilizado

Existem casos onde CsrfViewMiddleware.process_view pode não ter sido executado antes da sua view - os handlers 404 e 500, por exemplo - Mas você ainda precisa de um token CSRF em um formulário.

Solução: use requires_csrf_token()

Incluindo o token CSRF em uma view desprotegida

Podem existir algumas views que são desprotegidas e foram exceções pelo csrf_exempt, mas ainda precisam incluir um token CSRF.

Solução: use csrf_exempt() seguido do requires_csrf_token(). (ou seja requires_csrf_token precisa ser o decorador mais próximo da função).

Protegendo uma view para apenas um caminho

Uma view precisa da proteção CSRF apenas sob algumas condições, e pode não precisar em outras.

Solução: use csrf_exempt() para toda a função da view, e csrf_protect() para o caminho interno que precisa de proteção. Exemplo:

from django.views.decorators.csrf import csrf_exempt, csrf_protect


@csrf_exempt
def my_view(request):
    @csrf_protect
    def protected_path(request):
        do_something()

    if some_condition():
        return protected_path(request)
    else:
        do_something_else()

Protegendo uma página que usa AJAX sem um formulário HTML

Uma página faz uma requisição POST por AJAX, e a página não contém um formulário HTML com um csrf_token que irá causar que o cookie de CSRF obrigatório seja enviado.

Solução: use ensure_csrf_cookie() não view que envia a página.

Proteção CSRF em aplicações reutilizáveis

Já que é possível para o desenvolvedor desligar o CsrfViewMiddleware, todas as views relevantes nos apps contrib usam o decorador csrf_protect para garantir a segurançar destas aplicações contra CSRF. É recomendado que os desenvolvedores de apps reutilizáveis que querem as mesmas garantias também usem o decorador csrf_protect nas suas views.

Back to Top