Desenvolvimento· Arrumando a casa · parte 14
Separei o painel do site e pus o Access na porta.
Um script injetado no site público alcançava o painel pela sessão do operador. Separei o painel em app e endereço próprios, atrás do Access.

A sessão do operador valia em todas as páginas do site público. Um script injetado em qualquer página alcançaria o painel com essa sessão. Eu separei o painel do site e coloquei o Cloudflare Access na frente dele.
O risco morava na origem compartilhada. Origem é o endereço que o navegador usa para decidir quais páginas dividem a mesma sessão. Página pública e painel na mesma origem dividem alcance de cookie.
A origem pública carrega scripts que eu controlo só em parte
As páginas públicas carregam pixel, tag e scripts de terceiros. Cada script roda no contexto da página que o visitante abriu. Uma falha de injeção em uma página pública abre caminho para chamadas feitas com a sessão de quem estiver logado.
A sessão do operador valia para todas as páginas dessa origem. Um script injetado chamaria as rotas do painel usando a sessão válida. A proteção que impede a leitura do cookie pela página continua permitindo o uso dele nas chamadas.
Esse desenho fazia a segurança do painel depender de todas as páginas públicas. Cada página nova e cada script novo aumentavam a superfície de ataque do painel. O painel pagava o risco de um site feito para receber visita e medir campanha.
Nada ficava entre a internet e a tela de login do painel além do próprio aplicativo. Qualquer pessoa podia abrir a tela e tentar entrar. A lista de operadores e o código de e-mail carregavam sozinhos a defesa da entrada.
O painel virou um app próprio em endereço próprio
A saída foi tirar o painel de dentro do site. O painel virou um app próprio, com rotas e tratamento de sessão dele. O site público voltou a cuidar das páginas públicas e das tarefas dele.
O app do painel roda em endereço próprio, separado do endereço do site. A sessão do operador pertence só a esse endereço. Página pública aberta no mesmo navegador fica fora do alcance dessa sessão.
No Garfim, essa separação corrigiu um problema concreto de arquitetura. O painel tinha virado uma ilha dentro do site e repetia, de forma manual, o que o modelo de app já entregava pronto. App próprio resolveu a segurança e a manutenção na mesma mudança.
Um script plantado na página pública ainda pode tentar criar um cookie falso com o nome da sessão. Esse cookie chega ao painel como uma sessão inventada. A conferência de identidade barra a tentativa, e o efeito máximo é um painel deslogado.
O Access fecha a porta antes da tela de login
O Cloudflare Access fica na frente de todo o endereço do painel. Ele roda na borda da Cloudflare, antes de o pedido chegar ao app. Quem fica fora da lista de operadores nem enxerga a tela de login.
O operador entra em duas etapas separadas. Primeiro ele passa pelo Access com o código enviado a ele. Depois ele entra no painel com o login dele e o segundo fator.
O segundo fator amarra a entrada a algo além do código enviado por e-mail. No modelo que adotei, o painel pede código de uso único gerado no aparelho do operador.
A API confere tudo de novo a cada chamada do painel. Ela verifica a origem da chamada, a passagem pelo Access e a sessão do operador. Falta de configuração de conferência fecha o painel em vez de liberar a entrada.
Três produtos meus usam esse mesmo modelo de painel. O webmail central também fica atrás do Access. A repetição facilita a operação, porque cada painel novo nasce com a mesma porta de entrada.
O limite do modelo aparece fora do navegador
Apps nativos não passam pelo Access. O aplicativo de celular fala direto com a API, sem atravessar a porta que protege o painel no navegador. A proteção do painel cobre a operação no computador e deixa o app com as regras próprias dele.
Por isso a API mantém as conferências dela para todas as chamadas. Access fechado no painel e API aberta em outro caminho anulariam a separação. Cada caminho de entrada precisa da própria verificação de identidade e permissão.
Também existe um atrito de operação nessa escolha. O operador entra duas vezes, uma no Access e outra no painel. Cada ambiente novo pede a configuração do Access antes da publicação da API, sob risco de painel trancado.
Eu aceito esse atrito porque ele aparece uma vez na entrada. O risco anterior aparecia em todas as páginas públicas, todos os dias. Trocar risco permanente por atrito de login foi a conta que fechou a decisão.
Painel separado virou o padrão dos meus produtos
Hoje cada produto novo já nasce com o painel fora do site público. App próprio, endereço próprio e Access na frente formam o ponto de partida. O site público pode mudar de campanha e de script sem arrastar o painel junto.
A lição serve para qualquer operação com área restrita. Junte no mesmo endereço só o que pode dividir a mesma sessão com segurança. Página com script de terceiros e painel de operação pedem endereços separados.
Quem mantém painel dentro do site pode começar pelo inventário de scripts das páginas públicas. Cada pixel e cada tag listados respondem pela urgência da separação. Depois da separação, o deploy a partir da minha máquina publica site e painel como peças independentes, cada uma com a própria conferência.