Estou tentando entender todo o problema com o CSRF e maneiras apropriadas de evitá-lo. (Recursos que li, compreendi e concordo com: Folha de dicas sobre prevenção de RSC do OWASP , Perguntas sobre CSRF .)
Pelo que entendi, a vulnerabilidade em torno do CSRF é introduzida pela suposição de que (do ponto de vista do servidor da web) um cookie de sessão válido em uma solicitação HTTP recebida reflete os desejos de um usuário autenticado. Mas todos os cookies para o domínio de origem são magicamente anexados à solicitação pelo navegador; portanto, na verdade, todo o servidor pode inferir da presença de um cookie de sessão válido em uma solicitação: a solicitação vem de um navegador que possui uma sessão autenticada; não pode mais assumir nada sobre o códigoexecutando nesse navegador ou se realmente reflete os desejos do usuário. A maneira de evitar isso é incluir informações adicionais de autenticação (o "token CSRF") na solicitação, realizada por alguns outros meios que não o tratamento automático de cookies do navegador. Em termos gerais, o cookie da sessão autentica o usuário / navegador e o token CSRF autentica o código em execução no navegador.
Portanto, se você estiver usando um cookie de sessão para autenticar usuários do seu aplicativo da Web, também deverá adicionar um token CSRF a cada resposta e exigir um token CSRF correspondente em cada solicitação (mutante). O token CSRF faz uma viagem de ida e volta do servidor para o navegador, provando ao servidor que a página que faz a solicitação é aprovada por (gerado por, mesmo) por esse servidor.
Na minha pergunta, que é sobre o método de transporte específico usado para esse token CSRF nessa viagem de ida e volta.
Parece comum (por exemplo, no AngularJS , Django , Rails ) enviar o token CSRF do servidor para o cliente como um cookie (ou seja, no cabeçalho Set-Cookie) e, em seguida, fazer com que o Javascript no cliente o retire e o anexe. como um cabeçalho XSRF-TOKEN separado para enviar de volta ao servidor.
(Um método alternativo é o recomendado por exemplo , Express , em que o token CSRF gerado pelo servidor é incluído no corpo da resposta por meio da expansão do modelo no servidor, anexado diretamente ao código / marcação que o fornecerá de volta ao servidor, por exemplo como uma entrada de formulário oculta. Esse exemplo é uma maneira mais isométrica de fazer as coisas na Web 1.0, mas generalizaria bem para um cliente mais pesado em JS.)
Por que é tão comum usar o Set-Cookie como o transporte a jusante do token CSRF / por que essa é uma boa idéia? Imagino que os autores de todas essas estruturas considerassem suas opções com cuidado e não entendessem isso errado. Mas, à primeira vista, o uso de cookies para contornar o que é essencialmente uma limitação de design em cookies parece estúpido. De fato, se você usasse cookies como transporte de ida e volta (Set-Cookie: cabeçalho a jusante para o servidor informar ao navegador o token CSRF e Cookie: cabeçalho a montante para o navegador retorná-lo ao servidor), você reintroduziria a vulnerabilidade está tentando consertar.
Percebo que as estruturas acima não usam cookies para toda a ida e volta para o token CSRF; eles usam Set-Cookie a jusante, depois outra coisa (por exemplo, um cabeçalho X-CSRF-Token) a montante, e isso fecha a vulnerabilidade. Mas mesmo o uso de Set-Cookie como transporte a jusante é potencialmente enganador e perigoso; o navegador agora anexará o token CSRF a cada solicitação, incluindo solicitações XSRF maliciosas genuínas; na melhor das hipóteses, torna a solicitação maior do que precisa e, na pior das hipóteses, algum código de servidor bem-intencionado, porém mal orientado, pode realmente tentar usá-lo, o que seria muito ruim. Além disso, como o destinatário real do token CSRF é o Javascript do cliente, isso significa que esse cookie não pode ser protegido apenas com http.
Respostas:
Uma boa razão pela qual você meio que tocou é que, uma vez recebido o cookie CSRF, ele fica disponível para uso em todo o aplicativo no script do cliente para uso em formulários regulares e em POSTs AJAX. Isso fará sentido em um aplicativo pesado JavaScript, como o empregado pelo AngularJS (o uso do AngularJS não exige que o aplicativo seja um aplicativo de página única, portanto, seria útil onde o estado precisa fluir entre diferentes solicitações de página onde o valor de CSRF normalmente não pode persistir no navegador).
Considere os seguintes cenários e processos em um aplicativo típico para alguns prós e contras de cada abordagem que você descreve. Estes são baseados no padrão de token do sincronizador .
Abordagem do corpo da solicitação
Vantagens:
Desvantagens:
Cabeçalho HTTP personalizado (downstream)
Vantagens:
Desvantagens:
Cabeçalho HTTP personalizado (upstream)
Vantagens:
Desvantagens:
Cabeçalho HTTP personalizado (upstream e downstream)
Vantagens:
Desvantagens:
Set-Cookie
Vantagens:
Desvantagens:
Portanto, a abordagem do cookie é bastante dinâmica, oferecendo uma maneira fácil de recuperar o valor do cookie (qualquer solicitação HTTP) e usá-lo (a JS pode adicionar o valor a qualquer formulário automaticamente e pode ser empregada nas solicitações AJAX como cabeçalho ou como valor do formulário). Depois que o token CSRF for recebido para a sessão, não há necessidade de regenerá-lo, pois um invasor que utiliza uma exploração de CSRF não tem método de recuperar esse token. Se um usuário mal-intencionado tentar ler o token CSRF do usuário em qualquer um dos métodos acima, isso será impedido pela mesma política de origem . Se um usuário mal-intencionado tentar recuperar o lado do servidor do token CSRF (por exemplo, via
curl
), esse token não será associado à mesma conta de usuário, pois o cookie da sessão de autenticação da vítima estará ausente da solicitação (seria o invasor - portanto, não será associado ao servidor com a sessão da vítima).Além do padrão de token do sincronizador , também existe o cookie de envio duploMétodo de prevenção de CSRF, que obviamente usa cookies para armazenar um tipo de token de CSRF. É mais fácil de implementar, pois não requer nenhum estado do lado do servidor para o token CSRF. De fato, o token CSRF pode ser o cookie de autenticação padrão ao usar esse método, e esse valor é enviado via cookies como de costume com a solicitação, mas o valor também é repetido em um campo ou cabeçalho oculto, do qual um invasor não pode replicar como eles não podem ler o valor em primeiro lugar. No entanto, seria recomendável escolher outro cookie, além do cookie de autenticação, para que o cookie de autenticação possa ser protegido com a marcação HttpOnly. Portanto, esse é outro motivo comum para encontrar a prevenção de CSRF usando um método baseado em cookie.
fonte
O uso de um cookie para fornecer o token CSRF ao cliente não permite um ataque bem-sucedido porque o invasor não pode ler o valor do cookie e, portanto, não pode colocá-lo onde a validação do CSRF do lado do servidor exige.
O invasor poderá causar uma solicitação ao servidor com o cookie do token de autenticação e o cookie CSRF nos cabeçalhos da solicitação. Mas o servidor não está procurando o token CSRF como um cookie nos cabeçalhos da solicitação, está procurando na carga útil da solicitação. E mesmo que o invasor saiba onde colocar o token CSRF na carga, precisará ler seu valor para colocá-lo lá. Mas a política de origem cruzada do navegador impede a leitura de qualquer valor de cookie no site de destino.
A mesma lógica não se aplica ao cookie do token de autenticação, porque o servidor espera isso nos cabeçalhos da solicitação e o invasor não precisa fazer nada de especial para colocá-lo lá.
fonte
src='bank.com/transfer?to=hacker&amount=1000
qual o navegador solicitará, com os cookies associados para esse site (bank.com
)?Meu melhor palpite quanto à resposta: considere estas três opções para obter o token CSRF do servidor para o navegador.
Acho que o primeiro, o corpo da solicitação (embora demonstrado pelo tutorial do Express que vinculei na pergunta ), não é tão portátil para uma ampla variedade de situações; nem todo mundo está gerando todas as respostas HTTP dinamicamente; onde você acaba precisando colocar o token na resposta gerada pode variar bastante (em uma entrada de forma oculta; em um fragmento de código JS ou em uma variável acessível por outro código JS; talvez até em uma URL, embora isso geralmente pareça ruim. para colocar tokens CSRF). Portanto, embora exequível com alguma personalização, o número 1 é um lugar difícil de se fazer uma abordagem de tamanho único.
O segundo, cabeçalho personalizado, é atraente, mas na verdade não funciona, porque, embora o JS possa obter os cabeçalhos de um XHR invocado, ele não pode obter os cabeçalhos da página de onde foi carregada .
Isso deixa o terceiro, um cookie carregado por um cabeçalho Set-Cookie, como uma abordagem fácil de usar em todas as situações (o servidor de qualquer pessoa poderá definir cabeçalhos de cookie por solicitação e não importa que tipo de dados estão no corpo da solicitação). Portanto, apesar de suas desvantagens, era o método mais fácil para as estruturas implementarem amplamente.
fonte
Além do cookie de sessão (que é um tipo de padrão), não quero usar cookies extras.
Encontrei uma solução que funciona para mim ao criar um SPA (aplicativo de página única), com muitas solicitações AJAX. Nota: Estou usando Java do lado do servidor e JQuery do lado do cliente, mas não há coisas mágicas, então acho que esse princípio pode ser implementado em todas as linguagens de programação populares.
Minha solução sem cookies extras é simples:
Lado do Cliente
Armazene o token CSRF que é retornado pelo servidor após um login bem-sucedido em uma variável global (se você quiser usar armazenamento na Web em vez de um global, tudo bem, é claro). Instrua o JQuery a fornecer um cabeçalho X-CSRF-TOKEN em cada chamada AJAX.
A página principal "índice" contém este snippet JavaScript:
Lado do servidor
No logon sucessivo, crie um token CSRF aleatório (e longo o suficiente), armazene-o na sessão do lado do servidor e devolva-o ao cliente. Filtre determinadas solicitações de entrada (confidenciais) comparando o valor do cabeçalho X-CSRF-TOKEN com o valor armazenado na sessão: elas devem corresponder.
Chamadas AJAX confidenciais (dados de formulário POST e dados GET JSON) e o filtro do lado do servidor que as captura, estão no caminho / dataservice / *. As solicitações de logon não devem atingir o filtro, portanto, elas estão em outro caminho. As solicitações de HTML, CSS, JS e recursos de imagem também não estão no caminho / dataservice / *, portanto, não são filtradas. Eles não contêm nada secreto e não podem causar danos, por isso está bem.
fonte