33 pontos por GN⁺ 2025-03-04 | 1 comentários | Compartilhar no WhatsApp
  • Ao pensar sobre Cross-Site Request, no início não ficava claro por que proteção contra CSRF e CORS eram ambas necessárias. Mas, para explicar isso, são necessárias muitas palavras

CSRF e CORS

  • CSRF (Cross-Site Request Forgery)
    • Era comum no passado, mas hoje quase não é um problema, já que a maioria dos frameworks web oferece proteção por padrão
    • Forma de ataque: induzir o usuário a clicar em um formulário em um site malicioso para enviar uma requisição cross-site
    • Forma de defesa: verificar se a requisição não veio de outro site
  • CORS (Cross-Origin Resource Sharing)
    • Faz parte da especificação HTTP e define como permitir determinadas requisições cross-site
    • Usa preflight request e cabeçalhos de resposta para especificar de quais origens (origin) as requisições podem ser enviadas

Então, requisições cross-site são permitidas por padrão e por isso a proteção contra CSRF é necessária, ou são bloqueadas por padrão e o CORS é necessário para permiti-las? A resposta é as duas coisas.

Funcionamento básico

  • Política de mesma origem (Same-origin policy)
    • Política de segurança imposta pelo navegador
    • Em geral, escrita (Write) cross-site é permitida, mas leitura (Read) é proibida
    • Por exemplo, o navegador permite uma requisição POST via formulário, mas não permite ler a resposta
  • Política de cookies SameSite
    • Em 2019, o comportamento padrão dos cookies mudou
    • Antes, os cookies sempre eram enviados mesmo em requisições cross-site
    • O novo atributo SameSite foi adicionado, e o valor padrão passou a ser Lax
    • Em 2025, 96% dos navegadores suportam o atributo SameSite, e 75% suportam o novo padrão (Lax)
    • Porém, o Safari não o aplicou como padrão, e o UCBrowser ainda não oferece suporte
  • Diferença entre Site e Origin
    • Origin: combinação de protocolo + hostname + porta
    • Site: combinação de protocolo + domínio de topo + 1 (subdomínios e portas são ignorados)

CORS

  • CORS é uma forma de permitir exceções à política de mesma origem para determinadas origens (origin)
  • Antes de enviar a requisição, o navegador envia uma preflight request do tipo OPTIONS
  • O servidor define as regras permitidas por meio dos cabeçalhos de resposta (usando cabeçalhos Access-Control-*)
  • Tipos de requisição aos quais o CORS se aplica:
    • fetch e XMLHttpRequest
    • fontes web
    • texturas WebGL
    • imagens/frames de vídeo desenhados com drawImage em canvas
    • imagens usadas na propriedade CSS shape-outside
  • Mas o envio de formulários é uma exceção, e o CORS não se aplica
    • A tag <form> do HTML 4.0 já permitia requisições cross-site há muito tempo
    • Portanto, servidores antigos já deveriam ter sido projetados para se defender de ataques CSRF
    • Para compartilhar a resposta, o servidor precisa definir Access-Control-Allow-Origin, mas a própria requisição é aceita mesmo sem preflight

Pergunta: como a política SameSite e esse comportamento mantêm consistência entre si?

Métodos de proteção contra CSRF

  • Requisições de escrita cross-site são permitidas, mas a resposta não é compartilhada
    • A maioria dos sites não quer permitir escrita cross-site
  • Método padrão de defesa contra CSRF
    • Incluir e validar um token CSRF específico por usuário na requisição
    • Formas de uso:
      • Envio de formulário: adicionar o token em um campo oculto (hidden input)
      • Requisições JS: armazenar em cookie ou tag meta, depois incluí-lo no cabeçalho ou nos parâmetros da requisição
  • Requisições JS originalmente já são bloqueadas por padrão quando são cross-site
    • Mas são permitidas em requisições same-site
    • Ao incluir o token CSRF, é possível validar todas as requisições da mesma forma
  • Benefícios adicionais de segurança
    • Funciona com base na premissa de que o navegador deve bloquear por padrão a leitura da resposta
    • É mais seguro do que verificar apenas o cabeçalho Origin

Pergunta: em alguns frameworks, o token CSRF muda periodicamente. Por quê?

O papel do navegador

  • O ponto central da segurança web depende de o navegador ser confiável
  • O navegador:
    • impõe a política de mesma origem
    • bloqueia a leitura quando a resposta não é permitida
    • decide se aplica o padrão SameSite=Lax
    • implementa o CORS e envia preflight requests seguras

Precisamos confiar no navegador que estamos usando.

Conclusão

  • Se SameSite=Lax fosse suportado por 100% dos navegadores, a segurança seria ainda maior, mas
    atualmente ainda existe a exceção de permitir requisições POST cross-site
  • Portanto, desenvolvedores ainda precisam considerar continuamente a proteção contra CSRF

"A internet está ficando cada vez mais segura, mas ao mesmo tempo a compatibilidade com o passado está diminuindo."

Fonte

  1. Same-origin policy
  2. caniuse SameSite cookie attribute
  3. OWASP CSRF cheatsheet
  4. CORS wiki with requirements
  5. CORS spec
  6. CORS on MDN
  7. Preflight request
  8. Origin request header
  9. Origin and Site

1 comentários

 
GN⁺ 2025-03-04
Comentário do Hacker News
  • CORS é um mecanismo pelo qual o servidor informa explicitamente ao navegador quais requisições cross-origin podem ler a resposta

    • Por padrão, o navegador bloqueia scripts cross-origin de ler a resposta
    • A menos que seja explicitamente permitido, o domínio que fez a requisição não pode ler a resposta
    • Por exemplo, um script em evil.com pode tentar enviar uma requisição para bank.com/transactions para ler o histórico de transações da vítima
    • O navegador permite que a requisição chegue até bank.com, mas impede que evil.com leia a resposta
  • A proteção contra CSRF impede que requisições cross-origin maliciosas executem ações não autorizadas em nome de um usuário autenticado

    • Por exemplo, um script em evil.com pode enviar uma requisição para executar uma ação em bank.com (por exemplo, transferir dinheiro para bank.com/transfer?from=victim&to=hacker)
    • A proteção contra CSRF no lado do servidor de bank.com rejeita isso, provavelmente porque a requisição não inclui um token CSRF secreto
  • A proteção contra CSRF trata de proteger escritas, enquanto CORS trata de proteger leituras

  • Requisições iniciadas por JS, por padrão, não permitem cross-site

    • É possível iniciar uma requisição cross-site usando fetch() com apenas os cabeçalhos permitidos
  • Acho que existe uma explicação melhor sobre esse tema

    • Link de blog relacionado fornecido
  • Resposta à pergunta do post do blog

    • O elemento <form> do HTML 4.0 pode enviar requisições simples para qualquer origem
    • Houve uma pergunta sobre como isso se alinha com a iniciativa SameSite nesse contexto
  • Em 2022, foi adicionado um parágrafo ao artigo do MDN sobre CORS para esclarecer a origem do termo "requisições simples"

    • Antes, só dizia que isso não era mencionado na especificação do fetch
    • Em 2019, não havia menção a casos em que as proteções de CSRF do navegador davam suporte a SameSite=Lax ou o definiam como padrão
  • É confuso que SameSite tenha sido adicionado independentemente do preflight do CORS

    • Fico pensando por que os fabricantes de navegadores não exigiram preflight para todas as requisições POST cross-origin
  • Pode parecer seguro mesmo sem usar csrf, mas algumas bibliotecas (por exemplo, django rest framework) conseguem processar formulários HTML quando o cabeçalho content-type está definido

    • Isso permite publicar um formulário no site do usuário e enviar requisições em nome dele
  • Pergunta sobre por que tokens CSRF são rotacionados

    • O OWASP diz que isso é mais seguro, mas não entendo bem o motivo
  • Pedido de um fluxograma para esse tema complexo

    • Deseja uma nova plataforma de aplicações e um novo conjunto de padrões
  • Essas coisas não ajudam com rastreamentos de diagnóstico fáceis

    • Já tive várias vezes erros opacos em casos de uso legítimos que não estavam configurados corretamente
  • Não entendo por que, antes do surgimento do CORS, era possível enviar requisições para endpoints arbitrários diferentes da origem da página, mas sem poder ver a resposta

    • Fico curioso se isso entrou por acidente na especificação, se foi intencional por prever XSS, ou se um navegador líder fazia assim e os outros seguiram
  • Confusão sobre a proteção contra CSRF

    • Gostaria de entender o que impede um atacante de obter um token CSRF em goodsite.com, colocá-lo em badsite.com e enganar Alice para enviar de badsite.com uma requisição para goodsite.com