Estou escrevendo um aplicativo (Django, acontece) e só quero ter uma idéia do que realmente é um "token CSRF" e como ele protege os dados. Os dados da postagem não são seguros se você não usar tokens CSRF?
Estou escrevendo um aplicativo (Django, acontece) e só quero ter uma idéia do que realmente é um "token CSRF" e como ele protege os dados. Os dados da postagem não são seguros se você não usar tokens CSRF?
Respostas:
www.mybank.com
mybank.com
resultará em uma solicitação (conceitualmente) do formulário http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>
. (O número da sua conta não é necessário, porque está implícito no seu login.)www.cute-cat-pictures.org
, sem saber que é um site malicioso.mybank.com
(requer um pouco de sorte!), Ele poderá incluir em sua página uma solicitação como http://www.mybank.com/transfer?to=123456;amount=10000
(onde 123456
está o número da conta das Ilhas Cayman) e 10000
é uma quantia que você pensava anteriormente estar feliz em possuir).www.cute-cat-pictures.org
página, então seu navegador fará essa solicitação.www.mybank.com
cookie e parecerá perfeitamente legítimo. Lá vai o seu dinheiro!Este é o mundo sem tokens de CSRF .
Agora, o melhor com tokens CSRF :
http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971
.mybank.com
será incluído em sua própria página da web quando ele o servir. É diferente cada vez que eles veiculam uma página para alguém.www.mybank.com
.Resultado: você mantém suas 10000
unidades monetárias. Eu sugiro que você doe parte disso para a Wikipedia.
(Sua milhagem pode variar.)
EDIT do comentário que vale a pena ler:
Vale a pena notar que o script www.cute-cat-pictures.org
normalmente não tem acesso ao seu token anti-CSRF www.mybank.com
devido ao controle de acesso HTTP. Esta observação é importante para algumas pessoas que enviam um cabeçalho Access-Control-Allow-Origin: *
para cada resposta do site sem saber o que é, apenas porque não podem usar a API de outro site.
www.cute-cat-pictures.org
normalmente não tem acesso ao seu token anti-CSRF www.mybank.com
devido ao controle de acesso HTTP. Esta observação é importante para algumas pessoas que enviam um cabeçalho Access-Control-Allow-Origin: *
para cada resposta do site sem saber o que é, apenas porque não podem usar a API de outro site.
Sim, os dados da postagem estão seguros. Mas a origem desses dados não é. Dessa forma, alguém pode induzir o usuário com JS a fazer login no seu site enquanto navega na página da web do invasor.
Para evitar isso, o django enviará uma chave aleatória no cookie e nos dados do formulário. Então, quando os usuários POSTs, ele verifica se duas chaves são idênticas. Caso o usuário seja enganado, o site de terceiros não pode obter os cookies do site, causando erro de autenticação.
O site gera um token exclusivo ao criar a página do formulário. Esse token é necessário para postar / obter dados novamente no servidor.
Como o token é gerado pelo seu site e fornecido apenas quando a página com o formulário é gerado, outro site não pode imitar seus formulários - eles não terão o token e, portanto, não podem postar no seu site.
O blog Cloud Under tem uma boa explicação dos tokens de CSRF.
Imagine que você tinha um site como o Twitter simplificado, hospedado em a.com. Os usuários conectados podem inserir algum texto (um tweet) em um formulário que está sendo enviado ao servidor como uma solicitação POST e publicado quando eles pressionam o botão de envio. No servidor, o usuário é identificado por um cookie contendo seu ID de sessão exclusivo, para que seu servidor saiba quem postou o Tweet.
O formulário pode ser tão simples quanto isso:
<form action="http://a.com/tweet" method="POST"> <input type="text" name="tweet"> <input type="submit"> </form>
Agora imagine que um bandido copia e cola esse formulário em seu site malicioso, digamos b.com. O formulário ainda funcionaria. Desde que um usuário esteja conectado ao seu Twitter (ou seja, ele tenha um cookie de sessão válido para a.com), a solicitação POST será enviada para
http://a.com/tweet
e processada como de costume quando o usuário clicar no botão Enviar.Até agora, isso não é um grande problema, desde que o usuário seja informado sobre o que exatamente o formulário faz, mas e se nosso bandido alterar o formulário da seguinte maneira:
<form action="https://example.com/tweet" method="POST"> <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad"> <input type="submit" value="Click to win!"> </form>
Agora, se um de seus usuários aparecer no site do bandido e clicar no botão "Clique para vencer!" , o formulário é enviado ao seu site, o usuário é identificado corretamente pelo ID da sessão no cookie e o Tweet oculto é publicado.
Se nosso bandido fosse ainda pior, ele faria o usuário inocente enviar este formulário assim que abrir sua página da Web usando JavaScript, talvez até completamente escondido em um iframe invisível. Basicamente, isso é falsificação de solicitação entre sites.
Um formulário pode ser facilmente enviado de qualquer lugar para qualquer lugar. Geralmente, esse é um recurso comum, mas há muitos outros casos em que é importante permitir apenas o envio de um formulário do domínio ao qual ele pertence.
As coisas ficam ainda piores se seu aplicativo da web não faz distinção entre solicitações POST e GET (por exemplo, no PHP usando $ _REQUEST em vez de $ _POST). Não faça isso! Os pedidos de alteração de dados podem ser enviados tão facilmente quanto
<img src="http://a.com/tweet?tweet=This+is+really+bad">
, incorporados a um site mal-intencionado ou até a um email.Como garantir que um formulário só possa ser enviado em meu próprio site? É aqui que o token CSRF entra. Um token CSRF é uma sequência aleatória e difícil de adivinhar. Em uma página com um formulário que você deseja proteger, o servidor geraria uma sequência aleatória, o token CSRF, o adicionaria ao formulário como um campo oculto e também se lembraria de alguma forma, seja armazenando-o na sessão ou definindo um cookie contendo o valor Agora, o formulário ficaria assim:
<form action="https://example.com/tweet" method="POST"> <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn"> <input type="text" name="tweet"> <input type="submit"> </form>
Quando o usuário envia o formulário, o servidor simplesmente precisa comparar o valor do campo publicado csrf-token (o nome não importa) com o token CSRF lembrado pelo servidor. Se as duas strings forem iguais, o servidor poderá continuar processando o formulário. Caso contrário, o servidor deve parar imediatamente de processar o formulário e responder com um erro.
Por que isso funciona? Há várias razões pelas quais o bandido do nosso exemplo acima não consegue obter o token CSRF:
Copiar o código-fonte estático da nossa página para um site diferente seria inútil, porque o valor do campo oculto muda com cada usuário. Sem que o site do bandido conheça o token CSRF do usuário atual, seu servidor sempre rejeitará a solicitação POST.
Como a página maliciosa do bandido é carregada pelo navegador do usuário de um domínio diferente (b.com em vez de a.com), o bandido não tem chance de codificar um JavaScript, que carrega o conteúdo e, portanto, o token CSRF atual do usuário de seu site. Isso ocorre porque os navegadores da web não permitem solicitações AJAX entre domínios por padrão.
O bandido também não pode acessar o cookie definido pelo seu servidor, porque os domínios não coincidem.
Quando devo me proteger contra a falsificação de solicitações entre sites? Se você pode garantir que não combina GET, POST e outros métodos de solicitação, conforme descrito acima, um bom começo seria proteger todas as solicitações POST por padrão.
Você não precisa proteger solicitações PUT e DELETE, porque, como explicado acima, um formulário HTML padrão não pode ser enviado por um navegador usando esses métodos.
Por outro lado, o JavaScript pode realmente fazer outros tipos de solicitações, por exemplo, usando a função $ .ajax () do jQuery, mas lembre-se de que, para que as solicitações AJAX funcionem, os domínios devem corresponder (desde que você não configure explicitamente o servidor da Web) .
Isso significa que, muitas vezes, você nem precisa adicionar um token CSRF às solicitações AJAX, mesmo que sejam solicitações POST, mas você deve evitar a verificação CSRF em seu aplicativo da Web se a solicitação POST for realmente uma solicitação. Solicitação AJAX. Você pode fazer isso procurando a presença de um cabeçalho como X-Requested-With, que as solicitações do AJAX geralmente incluem. Você também pode definir outro cabeçalho personalizado e verificar sua presença no lado do servidor. Isso é seguro, porque um navegador não adiciona cabeçalhos personalizados a um envio regular de formulário HTML (veja acima), portanto, o Sr. Bad Guy não pode simular esse comportamento com um formulário.
Se você tiver dúvidas sobre solicitações AJAX, porque, por algum motivo, não pode verificar um cabeçalho como X-Requested-With, basta passar o token CSRF gerado para o seu JavaScript e adicionar o token à solicitação AJAX. Existem várias maneiras de fazer isso; adicione-o à carga útil como faria um formulário HTML comum ou adicione um cabeçalho personalizado à solicitação AJAX. Desde que o servidor saiba onde procurá-lo em uma solicitação recebida e possa compará-lo com o valor original que lembra da sessão ou cookie, você será classificado.
A raiz de tudo isso é garantir que as solicitações sejam provenientes dos usuários reais do site. Um token csrf é gerado para os formulários e deve estar vinculado às sessões do usuário. É usado para enviar solicitações ao servidor, no qual o token as valida. Esta é uma maneira de proteger contra o csrf, outra seria verificar o cabeçalho do referenciador.