Como usar a proteção CSRF do Django¶
Para aproveitar das vantagens da proteção CSRF nas suas views, siga estes passos:
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).Em qualquer template que usa um formulário POST, use a tag
csrf_token
dentro do1
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.
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çãorender()
, views genéricas, ou apps contrib, você não precisa fazer isso, já que todas essas já fazem uso doRequestContext
.
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.