Por que é comum colocar tokens de prevenção de CSRF em cookies?

Estou tentando entender todo o problema com o CSRF e formas apropriadas de evitá-lo. (Recursos que li, entendi e concordo com:Folha de Cheat Prevenção CSRF 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, realmente todo o servidor pode inferir da presença de um cookie de sessão válido em uma solicitação que a solicitação vem de um navegador que possui uma sessão autenticada; não pode mais assumir nada sobre ocódigo executando nesse navegador, ou se realmente reflete os desejos do usuário. A maneira de evitar isso é incluir informações de autenticação adicionais (o "token CSRF") na solicitação, transportadas por outros meios além do tratamento automático de cookies do navegador. Falando livremente, o cookie de sessão autentica o usuário / navegador e o token CSRF autentica o código em execução no navegador.

Portanto, em poucas palavras, se você estiver usando um cookie de sessão para autenticar usuários de seu aplicativo da web, você também deve adicionar um token de CSRF a cada resposta e exigir um token de CSRF correspondente em cada solicitação (mutante). O token CSRF faz uma viagem de ida e volta do servidor para o navegador de volta ao servidor, provando ao servidor que a página que faz a solicitação é aprovada por (gerada por, mesmo) esse servidor.

Sobre a minha pergunta, que é sobre o método de transporte específico usado para esse token CSRF nessa ida e volta.

Parece comum (por exemplo,AngularJS, Django, Trilhos) para enviar o token CSRF do servidor para o cliente como um cookie (ou seja, em um cabeçalho Set-Cookie), e depois ter o Javascript no cliente, arrancá-lo do cookie e anexá-lo como um cabeçalho XSRF-TOKEN separado para enviar de volta o servidor.

(Um método alternativo é o recomendado por, e.Expressar, em que o token de CSRF gerado pelo servidor é incluído no corpo de resposta por meio da expansão de modelo do lado do servidor, anexado diretamente ao código / marcação que o fornecerá de volta ao servidor, por exemplo. como uma entrada de formulário oculto. Esse exemplo é uma maneira mais web 1.0 de fazer as coisas, mas generalizaria bem para um cliente mais JS-pesado.

Por que é tão comum usar o Set-Cookie como o transporte downstream para o token CSRF / por que isso é uma boa ideia? Eu imagino que os autores de todas essas estruturas consideraram suas opções com cuidado e não entenderam isso errado. Mas à primeira vista, usar cookies para contornar o que é essencialmente uma limitação de design em cookies parece tolo. De fato, se você usasse cookies como transporte de ida e volta (Set-Cookie: cabeçalho downstream para o servidor informar ao navegador o token CSRF e Cookie: cabeçalho upstream 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 viagem de ida e volta para o token CSRF; eles usam downstream Set-Cookie e, em seguida, algo a mais (por exemplo, um cabeçalho X-CSRF-Token) upstream, e isso fecha a vulnerabilidade. Mas mesmo usando o Set-Cookie como transporte a jusante é potencialmente enganoso e perigoso; o navegador agora anexará o token CSRF a todas as solicitações, incluindo solicitações genuínas de XSRF mal-intencionado; na melhor das hipóteses, isso torna o pedido maior do que o necessário e, na pior das hipóteses, um código bem-intencionado, mas equivocado, do servidor pode, na verdade, tentar usá-lo, o que seria muito ruim. Além disso, como o destinatário real do token CSRF é o Javascript do lado do cliente, isso significa que esse cookie não pode ser protegido apenas com http. Então, enviar o token CSRF para baixo em um cabeçalho Set-Cookie parece muito abaixo do ideal para mim.