A superfície de ataque do Hotwire

Prévia grátis 4 min de leitura

Um job em background renderiza uma partial. Ninguém está logado dentro desse job, porque ninguém é nada dentro de um job. A partial pede o usuário atual, recebe nil e renderiza a versão deslogada de um card. O Action Cable manda esse mesmo HTML para todo navegador inscrito no stream.

Isso não é um bug do Turbo. O Turbo fez o que você pediu. O problema é que "renderizar uma partial" deixou de significar "renderizar para quem pediu", e nada no código que você escreveu diz isso.

O Hotwire está cheio de momentos assim. O trabalho sai da requisição que você imaginava e vai para outra coisa: um job, um hover, uma fusão de DOM, um frame que busca a própria URL. Cada um é um lugar onde uma suposição trazida do Rails comum deixa de valer em silêncio.

O que este curso não é

O curso de nível Pleno "Turbo Streams: segurança" já trata de proteger broadcasts de Turbo Stream, e ele é dono de uma pergunta específica: quem pode receber um stream. Ele cobre nomes de stream assinados e por que uma assinatura prova a origem, e não a permissão. Mostra por que qualquer um decodifica um nome assinado sem a chave, e por que a página que você renderiza é a verdadeira fronteira de autorização. E mostra como restringir um stream a um único registro.

Tudo isso fica lá. Este curso supõe que você já decidiu corretamente quem pode se inscrever e faz a pergunta seguinte: com uma lista legítima de inscritos, o que ainda pode dar errado?

Quatro lugares em que a requisição não é o que você pensa

Aqui estão os quatro momentos que vale nomear logo, porque o resto do curso se apoia neles:

Momento O que falta ou muda
Um job de broadcast Sem requisição, sem sessão, sem usuário atual
Um hover Um GET real dispara antes de qualquer clique
Um morph O DOM é fundido, e não substituído
Um frame Uma URL que talvez você não controle renderiza dentro da sua página

Nenhum dos quatro é exótico. Esta aplicação faz três deles em páginas comuns, e o quarto está a um atributo de distância.

O que este curso cobre

A lição 2 é o centro do curso: o que um broadcast renderiza sem. Você vai ver o caminho real de renderização na gem turbo-rails instalada e ver uma partial renderizar com uma sessão vazia e o hostname example.org. Depois vai aprender a regra única que sai disso. Essa lição traz o desafio de código.

A lição 3 cobre Content Security Policy com Hotwire. Ela cobre o que um nonce protege, por que uma aplicação com importmap não sobe sem um e como o unsafe-inline se infiltra numa política. Mostra também como avaliar um gerador de nonce com honestidade, e não por boato. Esta aplicação tem uma política real, e nós a lemos.

A lição 4 cobre CSRF: como o Turbo acha o token e o envia, por que um fetch escrito à mão precisa fazer esse trabalho sozinho e o que quebra quando um formulário vai parar num fragmento em cache.

A lição 5 cobre o prefetch. O Turbo pede páginas sobre as quais você passou o mouse e nunca clicou. Se algum GET da sua aplicação muda estado, ele agora é uma mutação disparada por movimento do mouse, e o conserto não é uma configuração do Turbo.

A lição 6 cobre o morphing: o que um refresh de página com morph faz no DOM em que o usuário está, e como a identidade dos elementos é decidida. Mostra também por que "o nó sobreviveu" é uma afirmação de segurança, além de uma de UX.

A lição 7 junta as peças em frames, origens e o DOM como input não confiável, e deixa você com um checklist.

Comece pelo broadcast. É a falha que sai para produção em silêncio e alcança mais gente de uma vez.

Aula 1 de 7 · grátis

Continue com a aula 2

O que um broadcast renderiza sem ter

Mostra que broadcasts renderizam pelo ApplicationController.render sem requisição, sessão ou usuário, e como broadcasts de refresh evitam isso.

Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.

Digite para buscar...