Mover a interface administrativa para admin.example.com é uma melhoria real: mantém os cookies de administração longe das páginas públicas, dá às duas aplicações caches separadas e permite dirigir uma política de rede mais rigorosa para um único nome de host. Mas não é um controlo de CSRF, e não torna o código do site público seguro para ficar aberto diante de um administrador com sessão iniciada. A separação muda o que o navegador considera uma fronteira, não o que o servidor verifica, por isso faça estas quatro verificações antes de dizer que está terminado.

Leia origem e site como duas palavras diferentes

Uma origem é esquema, host e porta, portanto https://www.example.com e https://admin.example.com são origens diferentes. Um site, no sentido de SameSite, é esquema mais domínio registável, portanto esses dois nomes de host são normalmente o mesmo site. Essa diferença é toda a armadilha: o atributo SameSite não o ajudará entre subdomínios irmãos, porque o navegador não considera o pedido entre sites de todo. Aponte a interface administrativa para um domínio registável realmente diferente, como admin-example.net, e o pedido passa mesmo a ser entre sites, e é aí que SameSite=Lax ou Strict começa a fazer trabalho em que pode confiar.

Teste-o no navegador em vez de raciocinar sobre o assunto.

Carregue o site público, abra as ferramentas de programador e veja que cookies o navegador associa a um pedido dirigido ao host administrativo. Se o cookie não tiver atributo Domain, é apenas do host e fica no seu próprio nome; se trouxer Domain=example.com, viaja para cada irmão, e o novo subdomínio não lhe deu nada para esse cookie.

Separe poder ler a resposta de poder enviar o pedido

A política da mesma origem restringe a leitura de respostas entre origens. Não impede que um pedido seja enviado, nem impede que um formulário leve credenciais que o navegador já tem. Um pedido simples, com tipo de conteúdo de formulário ou um GET simples, é entregue sem verificação prévia; depois o CORS decide se o script que chama pode ler a resposta. O CSRF vive inteiramente do lado do envio.

Por isso o servidor precisa de uma verificação explícita para operações que mudam estado. Um token de sincronização ligado à sessão, ou um cookie de duplo envio comparado no servidor, cobre o caso; comparar Origin ou Referer vale a pena como segunda porta, mas não como a única, porque nem todo o pedido leva o cabeçalho e nem todo o proxy o conserva. O guia da OWASP para prevenir CSRF trata o SameSite como uma camada entre várias exatamente por isso.

Decida o que a porta de rede prova de facto

Uma lista de saídas VPN permitidas à frente do host administrativo é um bom controlo e uma afirmação de identidade fraca. Prova que o pedido veio de um endereço que a VPN atribui, que pode ser partilhado por todos nessa saída, e não diz nada sobre que pessoa ou dispositivo está por trás. Trate-a como filtro de entrada, não como autenticação.

Mantenha-a independente das verificações ao nível do pedido. Se a lista for a única coisa entre um atacante e um ponto final que muda estado, uma rota mal configurada, um cliente em split-tunnel ou um portátil emprestado elimina o controlo por completo.

Registe também as rejeições fora dos intervalos esperados. Uma rajada delas é o sinal mais útil de que alguém está a sondar a fronteira que acabou de construir, e o silêncio é o sinal de que o filtro não está a ser alcançado de todo.

Mantenha cookies, início de sessão e autorização explícitos

O âmbito do cookie decide a maior parte do resultado. Um cookie do domínio pai é enviado ao host administrativo, por isso uma injeção de script no site público pode agir com a sessão de um administrador; um cookie apenas do host não pode. Prefira a forma apenas do host, acrescente o atributo Secure e use o prefixo __Host- onde a plataforma o suporta, porque esse prefixo exige Secure, Path=/ e nenhum atributo Domain. Leia o cabeçalho de resposta em vez do pote de cookies: Set-Cookie: __Host-admin_session=...; Secure; Path=/; HttpOnly; SameSite=Lax, sem atributo Domain. O navegador descarta um cookie __Host- que traga Domain, por isso um cookie que ainda aparece em hosts irmãos é prova de que o prefixo nunca foi aplicado.

Depois mantenha a autorização no servidor, por pedido, em cada ponto final administrativo, não apenas no início de sessão. Um pedido vindo de uma rede permitida ainda tem de ser autenticado e autorizado para a operação que pede; o nome do host não é um ator. Se as aplicações pública e administrativa partilharem um fluxo de início de sessão ou um armazém de sessões, escreva essa relação, porque é o caminho mais curto de um defeito no site público a uma ação administrativa.

Volte a verificar a fronteira após a separação

Execute os testes negativos, não apenas o caminho feliz: um formulário entre sites sem token tem de ser rejeitado, um token de outra sessão tem de ser rejeitado e nenhum GET deve mudar estado. Verifique os atributos dos cookies nas ferramentas de programador, confirme que a verificação de Origin dispara num pedido que não coincide e experimente o host administrativo fora do intervalo da VPN para ver o filtro em ação.

Nada disto elimina um defeito XSS dentro da própria aplicação administrativa. Um nome de host separado é uma fronteira de isolamento do lado do navegador com valor real, e não substitui a prevenção de execução de código inseguro nem a proteção de pedidos do lado do servidor. Depois da separação a lista é mais curta do que parece: origem distinta, cookies apenas do host, um token em cada alteração, um filtro de entrada em que não confia como identidade e autorização decidida por pedido.

Artigos relacionados