filipedeschamps / tabnews.com.br

Conteúdos para quem trabalha com Programação e Tecnologia.

Home Page:https://tabnews.com.br

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Mostrar mensagem de erro mais específica quando uma publicação for barrada pela Cloudflare

aprendendofelipe opened this issue · comments

Contexto

Algumas requisições POST podem retornar status 403 diretamente pela Cloudflare se eles detectarem alguma sequência de caracteres que possa ser utilizada de forma maliciosa.

Com isso, alguns conteúdos podem ser indevidamente impedidos de serem publicados por conterem algum script junto ao texto.

Após identificar que é um bloqueio pela Cloudflare, não é difícil encontrar uma forma alternativa de fazer a mesma publicação, pois geralmente é suficiente usar entidades no lugar de alguns caracteres, por exemplo / no lugar de /.

O problema é que a mensagem de erro que estamos apresentando hoje no front-end não dá nenhuma dica do que realmente está acontecendo, já que para qualquer status >= 401, estamos retornando a mensagem Não foi possível se conectar ao TabNews. Por favor, verifique sua conexão.

Execução

Podemos identificar que o retorno 403 está vindo da Cloudflare com algo parecido com o que foi feito no useUser, ou seja, verificando se:

response.status === 403 && webserver.isProduction && !response.headers.get('x-vercel-id')

Então podemos criar um desvio na lógica por aqui:

setGlobalErrorMessage('Não foi possível se conectar ao TabNews. Por favor, verifique sua conexão.');

e chamar

setGlobalErrorMessage('Com uma mensagem que dê dicas de como contornar o problema');

Precisamos pensar bem sobre a mensagem, pois podemos cair na mesma condição de erro caso o TabNews esteja sofrendo algum ataque e a Cloudflare esteja exigindo algum desafio para comprovar que é um humano fazendo a publicação.

Fala @aprendendofelipe, vi essa issue aqui e achei bem pertinente, queria colocar meus pensamentos.

Precisamos pensar bem sobre a mensagem, pois podemos cair na mesma condição de erro caso o TabNews esteja sofrendo algum ataque

Para esse caso seria interessante uma mensagem interna mais ou menos mostrando: "ok, 100 requisições em 1 segundo? Algum script malicioso? Temos um ataque rolando." (e ai da pra rodar mais validações além dessas) porém deixando a mensagem para a tela algo mais genérico para previnir dicas para uma possível ameaça?

Não necessariamente precisa ser o que tem hoje, mas alguma mensagem tipo "Comportamento proibido" ou "Conteúdo de texto não permitido", ou "Conteúdos de códigos devem estar dentro da sintaxe de código do markdown"

a Cloudflare esteja exigindo algum desafio para comprovar que é um humano fazendo a publicação

Um segundo ponto, fiquei com uma dúvida nisso. Caso a CF exija isso eu entendo que talvez não seja um comportamento de resposta a algum tipo de ataque ou script malicioso. Nesse caso teria que ter uma outra validação separado desse 403, talvez. Ao invés de retornar o erro na tela, deveria aparecer algum embed direto para conseguir resolver o desafio e então completar o post request?

Fala @guscsales, tudo certo?

Para esse caso seria interessante uma mensagem interna mais ou menos mostrando: "ok, 100 requisições em 1 segundo? Algum script malicioso? Temos um ataque rolando." (e ai da pra rodar mais validações além dessas) porém deixando a mensagem para a tela algo mais genérico para previnir dicas para uma possível ameaça?

Quando a Cloudflare bloqueia a requisição, independentemente do motivo, ela apenas devolve o erro 403. Não temos como alterar o erro que é retornado nessa resposta, pois não passa pelo nosso back-end. Então a proposta da issue é sobre melhorar o que mostramos no front-end quando a requisição retornar um 403 que não foi gerado por nós.

Caso a CF exija isso eu entendo que talvez não seja um comportamento de resposta a algum tipo de ataque ou script malicioso. Nesse caso teria que ter uma outra validação separado desse 403, talvez.

Isso, o problema é justamente como separar. Quando a Cloudflare decide que só vai liberar acessos que passarem primeiramente pelo desafio, então toda requisição de JSON será bloqueada até que uma requisição HTML passe pelo desafio. Esses casos também retornam 403, mas talvez tenha algum cabeçalho que dê para identificar o motivo do bloqueio. É isso que precisamos descobrir. Se não tivermos como diferenciar, então talvez a mensagem precise ser mais abrangente para englobar o dois casos.

Ao invés de retornar o erro na tela, deveria aparecer algum embed direto para conseguir resolver o desafio e então completar o post request?

Quanto a isso não precisamos nos preocupar, pois a Cloudflare que gerencia. Normalmente não precisa de nenhuma interação do usuário, mas as vezes precisa e, nesses casos, ela já carrega a página onde o usuário deverá interagir. O que temos que ter em mente aqui é que ela só consegue enviar o desafio quando o usuário está requisitando algum HTML, então não vai ser enviado nenhum desafio quando ela bloqueia requisições para a API (assim como quando se navega em SPA).

mas talvez tenha algum cabeçalho que dê para identificar o motivo do bloqueio.

boa, fiz uma pesquisa rápida aqui e parece que existem alguns headers sim, por exemplo o CF-RAY que cria um hash para o visitante, mas pela documentação parece que podem ter outros. Tem que explorar um pouco mais.

Você tem algum caso de teste que retorne esse 403 já que de pra fazer em ambiente de desenvolvimento? Posso pegar para analisar isso, depois de descobrir o header de fato podemos pensar numa mensagem personalizada, que acha?

Ainda não temos nenhum teste que simule respostas da Cloudflare

Certo, mas na teoria se eu rodar o projeto em ambiente de dev seguindo o read.me ele irá passar pelo cloudflare? Assim posso tentar simular alguns casos.

Certo, mas na teoria se eu rodar o projeto em ambiente de dev seguindo o read.me ele irá passar pelo cloudflare?

Assim não vai passar pela Cloudflare. Na verdade as requisições nem vão sair da sua máquina se você estiver rodando localmente.

O ambiente de homologação do TabNews também não vai ajudar, pois não usa a Cloudflare. E não recomendo testar em produção.

Se eu entendi, você quer testar na prática o comportamento da Cloudflare, certo? Nesse caso, uma boa opção é criar um projeto simples, específico para o teste, e colocar a Cloudflare como proxy. Se for hospedar o teste na Vercel, a documentação deles pode ajudar com a integração:

https://vercel.com/docs/integrations/cloudflare

O projeto de teste até poderia ser um clone do TabNews, mas para esse caso não vale a pena, já que você teria que subir também um PostgreSQL, configurar um servidor de email, além de envolver muitas outras variáveis no seu teste.


Como exemplo para os testes, uma requisição que foi bloqueada pela Cloudflare continha no body o texto /proc/version e outra continha

`curl -fsSL https://bun.sh/install | bash`

Já para forçar a Cloudflare a exigir desafio para todos os acessos, uma forma simples é habilitar em Quick Actions:

image