Segurança Web e sessões

Origem, sessões, autenticação e biometria, CSP/SRI, XSS, SQL, CSRF e autorização.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

A loja recebe GET /faturas/42 com um cookie de sessão. O navegador aplica regras entre sites, mas o servidor não pode depender delas para autorizar a leitura: qualquer cliente pode construir o pedido. Temos duas decisões separadas, o que o navegador deixa um site fazer e o que o servidor permite à conta autenticada.

Mesma origem não significa mesmo site

Uma origem é o trio esquema, host e porta efetiva. https://loja.example/a e https://loja.example/b têm a mesma origem. http://loja.example, https://api.loja.example e https://loja.example:8443 têm origens diferentes da primeira.

A política da mesma origem restringe, entre outras coisas, a leitura de respostas por código de outra origem. Não proíbe todos os pedidos: um formulário pode enviar certos pedidos a outra origem, por isso esta política não elimina CSRF. CORS permite ao servidor conceder determinadas leituras entre origens; não substitui a autorização do servidor.

Um preflight CORS consulta permissões antes de certos pedidos, conforme método, cabeçalhos e outros requisitos do navegador. Não pergunta se a operação tem efeitos no servidor: um pedido que dispensa preflight pode alterar estado se o servidor o implementar assim. O servidor mantém a responsabilidade pela autorização e proteção CSRF.

Frames de origens diferentes têm acesso ao DOM restringido, mas podem comunicar por postMessage. O recetor valida a origem, o remetente esperado e a estrutura da mensagem antes de agir. Um frame pode ter a mesma origem do pai; incorporar um frame não o torna automaticamente uma fronteira isolada de outra origem.

“Site”, usado por SameSite, agrupa origens segundo regras de domínio registável e esquema. Dois subdomínios podem ser same-site e continuar cross-origin. Não uses os dois termos como sinónimos.

XS-Leaks: observar sem ler a resposta

A política da mesma origem não esconde todos os efeitos de um recurso. Suponhamos que um endereço de outro site devolve uma imagem válida quando a pessoa tem sessão e uma página HTML quando não tem. Se o navegador envia o cookie relevante e permite incorporar o recurso como imagem, a página atacante pode distinguir o evento de carregamento do evento de erro. Não lê o HTML nem executa código na origem da vítima; infere um estado através do resultado observável.

Este caso é um XS-Leak, uma fuga entre sites. Difere de XSS, que executa código no contexto da aplicação, e de CSRF, que induz uma operação não escolhida pela vítima. Bloquear a leitura do corpo não elimina o sinal de carregamento. A explorabilidade depende das regras de cookies, incorporação e isolamento do navegador. A defesa deve retirar o sinal sensível ou impedir a incorporação nesse contexto, usando as políticas adequadas; cifrar o transporte não remove o sinal.

Sessões e cookies

O servidor cria um identificador imprevisível que referencia estado de sessão. O navegador devolve-o, habitualmente num cookie. Roubar o identificador pode permitir usar a sessão sem conhecer a palavra-passe. Segue o ciclo:

  1. a utilizadora prova a identidade no login;
  2. o servidor cria a sessão e responde com Set-Cookie;
  3. o navegador envia o cookie em cada pedido;
  4. o servidor procura a sessão e decide se aquela conta pode executar aquela operação.
Set-Cookie: sessao=<valor-aleatorio>; Secure; HttpOnly; SameSite=Lax; Path=/
ControloO que fazLimite
SecureRestringe envio a transporte seguro, com exceções do navegador para desenvolvimentoNão impede código do mesmo site de fazer pedidos
HttpOnlyImpede leitura do cookie por APIs de JavaScriptXSS ainda pode executar ações autenticadas
SameSite=LaxRestringe envio em contextos cross-sitePode permitir navegações de topo com métodos seguros; não autoriza operações
Renovar a sessão após loginEvita conservar um identificador fixado antes da autenticaçãoNão corrige um roubo posterior
Expirar e invalidar no servidorTermina a autoridade da sessãoApagar só o cookie local não invalida uma cópia roubada

Não coloques o identificador em URLs ou logs. Usa os mecanismos da framework e verifica a política de expiração e logout. Um cookie previsível como abc123 não é um exemplo de segredo adequado.

Neste modelo, o cookie transporta uma referência opaca e a autoridade vive na sessão do lado do servidor, verificada a cada operação. O erro é confiar em atributos fornecidos pelo cliente sem verificar autenticidade, integridade e validade: valores simples como pontos, papéis ou permissões podem ser alterados no cliente e voltariam a ser lidos como factos, que é o envenenamento de cookie das notas de estudo.

Guardar autoridade no cliente só é aceitável com verificação explícita pelo servidor, por exemplo token com assinatura ou MAC sob chave do servidor, mais expiração, audiência, contexto e autorização por operação. Sem essa verificação, trata o cookie como entrada controlada pelo cliente. O RFC 7519, secções 2 e 3, descreve claims protegidas por assinatura ou MAC como um modelo diferente deste exemplo, que aqui não é adotado.

O servidor define atributos como SameSite na resposta Set-Cookie; o navegador aplica-os ao decidir o envio. Já cabeçalhos Sec-Fetch-* descrevem o contexto do pedido e são produzidos pelo navegador. O servidor pode usá-los como informação adicional para recusar contextos indevidos. Não substituem autenticação ou autorização: clientes fora do navegador podem construir os próprios cabeçalhos.

Autenticação e palavras-passe

Armazena palavras-passe com uma função de derivação adequada, como Argon2id, e um sal distinto por entrada. O sal pode ser público. Com sais distintos, a mesma palavra-passe não produz a mesma referência em contas diferentes; o atacante não pode reutilizar uma única tabela pré-computada para todos os sais. O custo da função dificulta tentativas offline. Cifra reversível e hash rápido simples não cumprem este objetivo.

Limites de tentativas e fatores adicionais protegem outros riscos. Duas palavras-passe continuam no mesmo fator, algo que sabes. Autenticação multifator combina categorias independentes, como um segredo e um dispositivo. Um processo de recuperação fraco pode contornar a proteção do login.

Um sal não evita que a pessoa reutilize a mesma palavra-passe noutro serviço. Se o atacante a descobrir num serviço, pode experimentar essa palavra-passe em outro, mesmo que os sais sejam diferentes. Evitar reutilização e proteger a recuperação responde a esse risco; sal e custo da função protegem o armazenamento.

U2F, Universal 2nd Factor, usa um autenticador que protege uma chave privada e responde criptograficamente a um desafio ligado ao serviço. O servidor verifica com a chave pública registada. Não é outro nome para duas palavras-passe ou para qualquer MFA: a ligação ao serviço distingue-o de códigos que o utilizador pode entregar a uma página de phishing. A proteção depende também da validação da origem pelo cliente e da recuperação da conta.

Autenticar uma entidade agora

Um MAC válido sobre uma mensagem mostra que alguém com a chave a criou. Não demonstra, sozinho, que o interlocutor está presente agora, porque uma gravação antiga pode continuar válida. Autenticação de entidade precisa de ligar a prova à interação atual, além de à identidade esperada.

Num esquema abstrato de desafio-resposta, o verificador envia um nonce novo. A resposta autentica esse nonce e o contexto, incluindo papéis e identidades, com uma construção adequada. O verificador aceita apenas o desafio pendente e invalida-o depois do uso. Repetir um desafio, aceitar uma resposta de outro contexto ou esquecer a invalidação pode permitir replay. Este esquema descreve requisitos; não substitui um protocolo analisado.

Uma autenticação inicial também não autoriza todos os objetos da aplicação. A sessão representa a identidade autenticada, e cada operação continua a precisar de autorização.

Biometria: erros e limiares

Uma comparação biométrica não é igualdade exata: ruído e variação exigem um limiar. Tornar a decisão mais exigente tende a reduzir aceitação de impostores e a aumentar rejeição de pessoas legítimas. Distingue os dois denominadores.

Neste modelo de tentativas de autenticação:

FAR=tentativas de impostores aceitestentativas de impostores.FAR=\frac{\text{tentativas de impostores aceites}}{\text{tentativas de impostores}}. FRR=tentativas legıˊtimas rejeitadastentativas legıˊtimas.FRR=\frac{\text{tentativas legítimas rejeitadas}}{\text{tentativas legítimas}}.

Em 10 000 tentativas de impostores, oito são aceites: FAR de 0,08%. Em 500 tentativas legítimas, vinte são rejeitadas: FRR de 4%. Estas taxas não dizem que 0,08% de todas as aceitações são impostores; essa proporção também depende da frequência de impostores.

FMR e FNMR descrevem erros de comparação; FAR e FRR podem descrever o sistema de autenticação completo. A definição e o protocolo de ensaio têm de acompanhar os números. Resistência a apresentações falsas, como uma fotografia, também exige avaliação própria. Uma característica biométrica não é um segredo facilmente substituível depois de exposto; protege modelos biométricos e prevê alternativas de acesso.

Não há uma regra geral que obrigue FAR e FRR a serem iguais. Um controlo de acesso a um laboratório e o desbloqueio de um dispositivo pessoal podem atribuir custos diferentes à aceitação indevida e à rejeição legítima. O ponto de igualdade é uma referência de comparação, não automaticamente o limiar adequado ao sistema.

XSS e o contexto de saída

Em XSS refletido, a entrada volta na resposta; em XSS armazenado, fica guardada antes de atingir outra pessoa; em XSS baseado no DOM, código do cliente coloca dados num ponto que os interpreta como código ou marcação.

// Vulnerável, a entrada torna-se HTML.
echo "<p>Olá, " . $_GET["nome"] . "!</p>";
// Para conteúdo textual dentro deste elemento HTML:
echo "<p>Olá, " . htmlspecialchars($_GET["nome"], ENT_QUOTES, "UTF-8") . "!</p>";

Antes da correção, o navegador recebe <p>Olá, <script>…</script>!</p> e executa a marcação injetada. A segunda versão codifica dados no contexto texto HTML, por exemplo < passa a &lt;. Não é uma solução universal para JavaScript, CSS ou URLs, por isso se queremos aceitar HTML rico precisamos de sanitização apropriada. No cliente, textContent insere texto; innerHTML interpreta marcação. Uma política CSP bem definida pode limitar certos ataques, mas não substitui a eliminação do ponto de injeção.

Um cookie HttpOnly não torna um XSS inofensivo. O código malicioso pode pedir uma transferência na origem legítima, mesmo sem ler o cookie.

Ler uma política CSP

A política CSP é um controlo adicional do navegador; a resposta seguinte, da origem https://loja.example e sem outras políticas, mostra como a ler:

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example; object-src 'none'
Recurso propostoResultado previsto nesta política
Script externo em https://loja.example/app.jsPermitido por 'self'
Script externo em https://cdn.example/lib.jsPermitido pela origem indicada
Script externo em https://outro.example/a.jsBloqueado pela lista de scripts
Script inline sem nonce nem hash autorizadoBloqueado
Objeto incorporado por objectBloqueado por 'none'

default-src fornece um valor de recurso por defeito às diretivas que têm essa regra de fallback; script-src substitui esse fallback para scripts. A lista permite a origem do CDN, não garante que todos os seus ficheiros sejam seguros. Nonces e hashes permitem selecionar scripts segundo regras próprias. Content-Security-Policy-Report-Only relata violações, mas não aplica o bloqueio. CSP complementa a prevenção de XSS.

SRI: fixar os bytes esperados

Subresource Integrity, ou SRI, associa um recurso a um hash esperado no atributo integrity. O navegador verifica os bytes recebidos antes de usar o recurso. Para um script de outra origem, é necessário suporte CORS adequado; crossorigin="anonymous" pede esse modo de acesso.

Este exemplo calcula o valor correspondente a um ficheiro local fictício. Não descarrega nem executa scripts externos.

Calcular uma referência SRI
import base64
import hashlib

original = b'console.log("ola");\n'
alterado = b'console.log("adeus");\n'

def sri(conteudo):
    resumo = hashlib.sha384(conteudo).digest()
    return "sha384-" + base64.b64encode(resumo).decode("ascii")

print("integrity:", sri(original))
print("Alteração mantém o hash?", sri(original) == sri(alterado))
Resultado

Executa o código para ver a saída e os gráficos.

O prefixo identifica o algoritmo, seguido do digest codificado em Base64. Mudar os bytes altera a referência neste caso. SRI não prova que o código original é benigno e perde a utilidade se um atacante também puder trocar o HTML e o hash esperado. CSP e SRI impõem condições complementares: um hash SRI correto não autoriza uma origem proibida pela política aqui apresentada.

Injeção SQL

Concatenar a entrada na estrutura SQL permite que dados sejam interpretados como instruções. Com a entrada ' OR '1'='1, a condição nome = '<entrada>' expande-se para nome = '' OR '1'='1'. Essa condição é verdadeira para todas as linhas, por isso a consulta devolve Ana e Bruno.

Comparar SQL concatenado com SQL parametrizado
import sqlite3
db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE clientes (nome TEXT)")
db.executemany("INSERT INTO clientes VALUES (?)", [("Ana",), ("Bruno",)])
entrada = "' OR '1'='1"
vulneravel = "SELECT nome FROM clientes WHERE nome = '" + entrada + "'"
print("Concatenação:", db.execute(vulneravel).fetchall())
print("Parâmetro:", db.execute("SELECT nome FROM clientes WHERE nome = ?", (entrada,)).fetchall())
Resultado

Executa o código para ver a saída e os gráficos.

A consulta concatenada devolve Ana e Bruno. A parametrizada procura literalmente o valor do ataque e devolve uma lista vazia. Os parâmetros representam valores; normalmente não escolhem nomes de tabelas, colunas ou a direção da ordenação, por isso para essas escolhas mapeia opções permitidas para fragmentos fixos.

CSRF

Em CSRF, o atacante tenta induzir o navegador de uma vítima autenticada a enviar uma operação que ela não escolheu. Não precisa de ler a resposta. Imagina um serviço que altera o email por GET /email?novo=...: uma navegação induzida pode executar a alteração, inclusive em situações em que SameSite=Lax permite enviar o cookie. O servidor recebe um pedido válido do navegador da vítima, com cookie incluído, e não distingue intenção. Por isso, operações que alteram estado usam método próprio e exigem token ou validação de origem.

Não uses GET para alterações de estado. Para pedidos que alteram estado, usa as defesas da framework, como tokens ligados à sessão e validação de origem quando aplicável. SameSite é uma camada adicional. Um token público constante não prova a intenção do utilizador. XSS na origem pode contornar muitas defesas CSRF porque passa a agir no contexto legítimo.

Autorização por objeto

GET /faturas/42 precisa de verificar se a sessão pode ler a fatura 42. Esconder o link, usar um UUID ou verificar apenas que existe uma sessão não decide essa permissão. Uma referência direta a objeto sem a autorização adequada é frequentemente designada IDOR.

Numa resposta de teste, segue a entrada, identifica quem a interpreta, mostra a condição que falha e associa a defesa à mesma condição. SQL parametrizado não corrige uma autorização por objeto; HttpOnly não corrige XSS; HTTPS não impede pedidos maliciosos de um cliente autenticado.

Exercícios

XSS sem ler o cookie

Uma aplicação tem um XSS na sua origem, mas o cookie de sessão é HttpOnly. Qual conclusão é correta?

A tua resposta

Pista

Separa ler o segredo e agir com a sessão.

Solução

O script pode enviar pedidos autenticados na origem legítima: o navegador acrescenta o cookie, mesmo sem o script conseguir lê-lo. HttpOnly reduz uma forma de roubo do cookie, mas não impede estas ações. É necessário eliminar o XSS com tratamento adequado de dados e contexto.

  • O script pode continuar a tentar ações autenticadas na origem legítima.. HttpOnly impede ler o cookie por JS, mas o navegador pode enviá-lo em pedidos da aplicação.
  • O XSS fica automaticamente inofensivo.. O atacante ainda pode agir no contexto da página.
  • HttpOnly impede o envio do cookie ao servidor.. A restrição afeta leitura por APIs de JS, não o transporte normal do cookie.
  • HttpOnly substitui codificação da saída.. Não impede a execução do ponto de injeção.

Erros frequentes

Não apresentar atributos de cookie como defesa completa contra XSS.

Voltar à explicação
A alteração por navegação

Um serviço altera o email por GET e usa cookie SameSite=Lax. Uma navegação de topo pode transportar o cookie. Explica por que SOP e Lax não garantem proteção e propõe a correção.

Pista

O atacante precisa de ler a resposta para provocar a alteração?

Solução

SOP restringe leituras entre origens, mas não impede todas as navegações: o pedido chega na mesma ao servidor com o cookie. Lax tem exceções apropriadas a navegações seguras, e GET não devia alterar estado. Move a operação para um método de alteração e aplica a defesa CSRF da framework, com token ligado à sessão e validação de origem adequada. Só trocar GET por POST não chega: um formulário induzido também pode produzir um pedido POST. O envio do cookie depende dos atributos e do contexto, e a defesa deve verificar o pedido no servidor.

Confere a tua resposta:

  • Diz que SOP não bloqueia todos os pedidos.
  • Reconhece a possibilidade de envio Lax na situação dada.
  • Evita alterações por GET e aplica defesa CSRF adequada no servidor.

Erros frequentes

Trocar GET por POST sozinho não prova a intenção da vítima.

Voltar à explicação
A prova antiga volta

Um verificador aceita sempre a mesma resposta autenticada ao mesmo desafio. Um observador grava uma interação e reproduz a resposta mais tarde. A validade do MAC demonstra que a entidade está presente nessa segunda interação?

Pista

O observador precisa de conhecer a chave para copiar bytes?

Solução

Não. A resposta gravada mantém o MAC, mas não comprova uma participação nova. O desafio deve ser novo e a prova deve ligá-lo ao contexto esperado; o verificador só aceita o desafio pendente e deixa de o aceitar depois do uso. Autenticar a origem de uma mensagem não prova automaticamente presença atual.

Confere a tua resposta:

  • Explica que o MAC antigo pode continuar criptograficamente válido.
  • Exige desafio novo e resposta ligada à identidade e ao contexto.
  • Exige aceitar apenas o desafio pendente e invalidá-lo após uso.

Erros frequentes

Não propor apenas um MAC mais longo para um problema de repetição.

Voltar à explicação
Qual é o denominador?

Um ensaio tem 6 000 tentativas de impostores, das quais 12 são aceites, e 800 tentativas legítimas, das quais 40 são rejeitadas. Calcula apenas FAR em percentagem no modelo definido.

Pista

FAR usa só as tentativas de impostores no denominador.

Mais uma pista

Não divides 12 por 6 800 nem pelo número total de aceitações.

Solução

FAR =100×12/6 000=0,2%=100\times12/6\,000=0{,}2\%. FRR =100×40/800=5%=100\times40/800=5\%. São condicionais a classes diferentes. A fração de aceitações que pertence a impostores seria outra medida, dependente das contagens das duas classes.

Erros frequentes

Não somar as classes para calcular FAR ou FRR.

Voltar à explicação
CDN permitido, conteúdo alterado

A política efetiva é script-src https://cdn.example. Um script desse CDN é pedido com CORS adequado e integrity para a versão original. O CDN devolve bytes diferentes cujo digest não coincide. Passar CSP basta para executar? E um script de outra origem com o hash certo?

Pista

Há duas condições: origem permitida e integridade dos bytes.

Solução

Não. A origem passa CSP, mas a verificação SRI falha e o recurso não é usado. Um script de outra origem é bloqueado pela CSP dada mesmo com hash SRI correto. Se o atacante puder trocar também o HTML e a referência, a hipótese de integridade muda.

Confere a tua resposta:

  • Diz que a origem passa a regra CSP dada.
  • Diz que o hash SRI errado bloqueia o uso, assumindo verificação e CORS adequados.
  • Distingue origem permitida de bytes esperados e não afirma que SRI autoriza outra origem.

Erros frequentes

Não apresentar CSP como comparação de conteúdo nem SRI como lista de origens.

Voltar à explicação
Do login à fatura alheia

Uma utilizadora faz login, recebe o cookie de sessão e pede GET /faturas/42 de outra conta. O servidor verifica apenas que a sessão existe. Segue o ciclo da sessão, explica por que a fatura é devolvida e propõe a correção com validação. Depois a utilizadora faz logout e apaga apenas o cookie local. Uma cópia roubada do identificador ficou invalidada?

Pista

Separa identificar a conta de autorizar o objeto.

Mais uma pista

Um identificador imprevisível dificulta adivinhar, mas não decide permissões.

Solução

O login cria a sessão, o Set-Cookie entrega o identificador, o pedido devolve-o, o servidor encontra a sessão e autoriza mal: aceita qualquer sessão sem verificar se aquela conta pode ler a fatura 42. A correção verifica no servidor a relação entre utilizador autenticado e objeto pedido. Para validar, pede a própria fatura com a própria conta (deve permitir) e a alheia (deve negar). Apagar só o cookie local não invalida uma cópia roubada: a invalidação é no servidor.

Confere a tua resposta:

  • Segue login, Set-Cookie, pedido, procura da sessão e autorização.
  • Explica que sessão válida não autoriza qualquer objeto.
  • Explica por que apagar o cookie local não invalida uma cópia e exige invalidação no servidor.

Erros frequentes

Não apresentes HttpOnly, SameSite ou HTTPS como correção de uma autorização em falta.

Voltar à explicação
Sem acesso ao corpo, com um sinal

Num sistema fictício, um endereço devolve PNG com sessão e HTML sem sessão. Outra origem tenta incorporá-lo como imagem. Assume que o navegador envia o cookie e permite a incorporação; a página observa load no primeiro caso e error no segundo, mas não lê o corpo. Que informação consegue inferir? É necessário XSS na aplicação ou alterar dados da vítima? Avalia a afirmação «SOP impede a leitura, portanto HTTPS basta para impedir esta fuga».

Solução

O evento distingue ter sessão de não ter sessão. É um XS-Leak: o sinal revela estado sem acesso ao corpo. O cenário não exige executar código na origem da aplicação nem provocar uma alteração, pelo que não demonstra XSS ou CSRF. HTTPS protege o transporte, mas a página continua a observar o evento no navegador. É preciso impedir esta incorporação no contexto relevante ou eliminar a diferença observável associada ao estado sensível. Se o cookie não for enviado ou a incorporação for bloqueada, as hipóteses do ataque mudam.

Confere a tua resposta:

  • Inferi o estado de sessão a partir dos eventos dados.
  • Distingui XS-Leak de XSS e de alteração por CSRF.
  • Indiquei a hipótese de incorporação e uma defesa que retire o sinal.
Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.