1 pontos por GN⁺ 2024-03-31 | 1 comentários | Compartilhar no WhatsApp
  • A TablePlus vem observando o estado dos servidores apesar de semanas de tentativas de DDoS, sem bloquear IPs nem ativar o modo “Under Attack” do Cloudflare
  • Nos últimos 30 dias, houve cerca de 6 milhões de tentativas de download dos arquivos de instalação; só nos últimos 5 dias foram 800.126, e cada arquivo tem cerca de 200 MB por download
  • Mesmo durante o ataque, o uso de CPU dos servidores ficou na maior parte do tempo em 0–1%, e a infraestrutura foi montada para que cerca de 8 serviços de API e bancos de dados consigam processar bilhões de requisições por mês sem cache
  • O backend é agrupado em serviços monolíticos por aplicativo, usando implantação de um único binário em um novo VPS, sem Docker, Kubernetes nem ambiente de runtime
  • Uma configuração simples com frameworks Go/Rust, indexação de banco de dados, separação do banco de logs, proxy reverso com Nginx, Cloudflare CDN/R2 e throttling no envio de e-mails reduz o custo do ataque e a complexidade operacional

Semanas de tentativas de DDoS

  • Alguém enviou centenas de milhões de requisições aos servidores da TablePlus ao longo de várias semanas e tentou baixar os arquivos de instalação milhões de vezes
  • As tentativas de download dos arquivos de instalação chegaram a 800.126 nos últimos 5 dias e a cerca de 6 milhões nos últimos 30 dias
    • O tamanho do arquivo de instalação é de cerca de 200 MB por download
  • Com base nas chamadas de API dos últimos 30 dias, a maior parte do tráfego veio da UE, especialmente da Germany e do United Kingdom
    • Esse número não inclui requisições de download nem tráfego de CDN
  • No momento da redação do texto, o ataque ainda continua

Resposta prática: uma arquitetura feita para aguentar, não para bloquear

  • Não bloqueiam os endereços IP dos atacantes
  • Usam Cloudflare, mas não ativam o modo “Under Attack”
  • Mesmo durante o ataque, a CPU dos servidores permaneceu quase ociosa, na maior parte do tempo em 0–1%
  • Como o serviço consegue processar bilhões de requisições por mês sem problemas e sem grande impacto de custo, quase nenhuma medida extra foi necessária

Design simples de backend

  • O design do app TablePlus busca simplicidade, e os serviços de backend também são mantidos com a configuração mínima possível
  • Não usam serviços de renderização de terceiros como Vercel ou Netlify, porque eles podem virar gargalo durante um ataque ou gerar cobranças inesperadas
  • A visão deles é que usar o próprio servidor web evita essas limitações
  • No passado, monólitos podiam virar gargalo por causa de VPSs e processadores fracos, mas os VPSs atuais oferecem CPUs multicore, muita RAM e SSDs rápidos
    • SSDs rápidos e muita RAM aumentam bastante o desempenho do banco de dados
    • Se for bem implementado, um serviço monolítico em instância única também pode processar bilhões de requisições por mês

Como operam monólitos por aplicativo

  • Integram em um único serviço tudo o que cada app precisa: API, site, e-mail, pagamentos etc.
  • A implantação termina com um arquivo de configuração, build e deploy
  • Ao migrar o serviço para outro provedor de nuvem ou fazer uma nova implantação, o processo pode ser concluído rapidamente
  • Como há poucas dependências, fica mais fácil depurar e identificar gargalos
    • Mesmo quando ocorre um erro, geralmente há apenas um ou poucos serviços para verificar
  • Exemplos de frameworks monolíticos possíveis:
    • Golang: Echo, Gin
    • PHP: Laravel
    • Ruby: Rails
    • Rust: Actix, Rocket, Warp

Princípios de configuração para bilhões de requisições por mês

  • Escolhem frameworks web de alto desempenho, e a TablePlus prefere Golang e Rust
  • À medida que o conjunto de dados cresce, criam índices no banco de dados para reduzir o tempo de consulta
  • Para proteger o desempenho do negócio principal, separam o banco de dados principal do banco de logs e uso
    • O banco principal é para dados que não mudam ou cujo tamanho não cresce com o tempo
    • O banco de logs/uso é para dados que continuam crescendo com o passar do tempo
  • Na frente das APIs principais, colocam um proxy reverso para tratar e distribuir as requisições
    • Isso ajuda quando são necessários vários servidores
    • A TablePlus usa Nginx
  • Colocam tudo atrás do Cloudflare e configuram adequadamente cache, Argo e full SSL entre o Cloudflare e o servidor
  • Usam um CDN com proteção contra DDoS
    • A TablePlus prefere Cloudflare R2 e CDN em vez de Amazon CloudFront + S3, tanto para reduzir custos quanto para proteção
  • Manter arquivos grandes para download em um VPS sem CDN nem cache consome a largura de banda rapidamente
    • A TablePlus usa o Cloudflare CDN com largura de banda ilimitada
    • Se o Argo estiver ativado no mesmo domínio, o tráfego do Cloudflare CDN pode passar pelo Argo, e como a largura de banda do Argo não é gratuita, o custo pode aumentar bastante
  • Em requisições que exigem envio de e-mail pelo servidor, como recuperação de senha, usam throttling para proteger o mailer

Forma de implantação: executar binários sem contêineres

  • A TablePlus mantém o processo de implantação o mais simples possível, sem Docker, Kubernetes, contêineres nem configuração separada de ambiente de runtime
  • A unidade de implantação é o binário
    • Ele é copiado para um servidor Linux e executado como processo
    • É tratado de forma parecida com a execução do app TablePlus no macOS
  • O Linux Systemctl pode monitorar o processo e reiniciá-lo em caso de erro fatal
  • Executam de forma nativa para não desperdiçar CPU/RAM com camadas intermediárias como VM, virtualização ou gerenciadores de infraestrutura de terceiros
  • Escolhem Go e Rust porque são linguagens de alto desempenho e conseguem gerar arquivos binários para implantação

Proteções a ativar ao usar Vercel

  • Para proteger sites em situações assim, a Vercel oferece Spend Management e Attack Challenge Mode
    • Spend Management: permite definir limite de gasto soft ou hard
    • Attack Challenge Mode: é semelhante ao modo “Under Attack” do Cloudflare
  • Se você usa Vercel, é necessário deixar esses recursos ativados

1 comentários

 
GN⁺ 2024-03-31
Opiniões do Hacker News
  • Este texto parece autoelogio demais. “1 bilhão de requisições por mês” dá só algumas centenas de requisições por segundo, algo trivial, e é difícil até chamar isso de DDoS
    Além disso, o site fica atrás da Cloudflare, que é uma CDN, então entendo menos ainda por que isso seria visto como algo impressionante do ponto de vista de desempenho
    Por exemplo, não há um cenário razoável em que um arquivo de 200 MB não seja servido a partir do cache da CDN. Não é algo para se orgulhar dizer que o servidor da aplicação não lê 200 MB do disco e copia para o cliente a cada download; fazer isso seria um projeto obviamente ruim

    • Se o arquivo de 200 MB mencionado for o download do app cliente TablePlus em https://tableplus.com/download, a versão para Windows tem 183 MB e de fato está em cache na Cloudflare

      # curl -v https://files.tableplus.com/windows/5.9.2/TablePlusSetup.exec > /dev/null

      < cache-control: max-age=691200

      < cf-cache-status: HIT

      < age: 2980

    • Isso não é o tipo de coisa que, em uma empresa FAANG, normalmente se consideraria que exigiria mais de mil desenvolvedores? Não sei como dá para chamar só de autoelogio algo que até grandes empresas regularmente não conseguem fazer

    • É difícil olhar apenas como algumas centenas de requisições por segundo. A densidade das requisições não é uniforme ao longo do tempo e pode subir com frequência até 20 vezes a média

  • 4 TB por mês, na verdade, não é difícil de não considerar um ataque DDoS? Se fossem 4 TB por hora, daria para chamar de DDoS, mas 4 TB por mês são só 1,5 MB por segundo
    6 milhões de requisições por mês também são apenas 2 requisições por segundo. Nessa escala, o fato de operar como um serviço monolítico não parece muito relevante, especialmente considerando que a Cloudflare provavelmente atende a maior parte das requisições pelo cache da CDN

    • A esmagadora maioria da web são sites WordPress em hospedagem multi-inquilino de 5 a 20 dólares por mês, e, em organizações maiores, muitas vezes Drupal. Sem cache instalado e conectados diretamente ao banco de dados, a maioria dos sites da internet pode cair com apenas 4 requisições por segundo

      Pode parecer loucura, mas essa é a realidade. Antigamente, na Cloudflare, gerenciei proteção contra DDoS, WAF, firewall e projetos de segurança para clientes, e vi com frequência sites de clientes caírem só com web scraping ou taxas de requisições HTTP muito pequenas e baixas

      Números grandes ficam nas manchetes, mas o que a maioria das pessoas sente na prática são números pequenos

    • Um ataque de negação de serviço pode ser feito com apenas alguns KB por hora. Se você atingir um endpoint de API pesado do serviço-alvo, isso por si só pode derrubar o serviço; “Distributed” só significa que várias máquinas estão atacando ao mesmo tempo

      DDoS não exige necessariamente uma vazão enorme. Só que o que aparece nas notícias geralmente são os ataques grandes

      O objetivo desse tipo de ataque pode ser queimar a cota de banda do servidor de origem ou tornar o custo de banda insustentável. Dá para fazer isso muito barato com uma única máquina de ataque ou poucas delas. A maioria dos datacenters e provedores de hospedagem tem limite de banda ou cobra após certa quantidade, e empresas atacadas muitas vezes só percebem depois de receber uma fatura que não conseguem pagar

    • Tenho um site de download de um jogo com uns 50 jogadores no total. Ninguém usa, e pessoas reais provavelmente baixam o jogo algumas vezes por mês
      Só que um único arquivo zip de 2 GB gerou 5 TB de tráfego no mês passado, e isso continua há anos. Isso não é DDoS, é só um bot/crawler mal configurado que segue todos os links e não consegue cancelar o download

    • Parece ser algo como 1 TB por dia, mas ainda assim continua sendo muito pequeno

    • Acho que depende de quão irregular é o tráfego

  • Isto é apenas um site estático de marketing para um app desktop. Não há fórum de discussão, e o feedback é tratado via issues no GitHub
    É bem estranho se gabar de como é simples fazer deploy de um site estático de marketing e de como arquivos estáticos aguentam centenas de milhares de downloads por dia. E quem faz a mitigação aqui é a Cloudflare, não eles. Isso se esse tráfego minúsculo sequer precisar de mitigação

    Se eu sofresse um “ataque” desses, acho que nem perceberia até receber o e-mail mensal da Cloudflare dizendo “X TB transferidos, quase 100% de economia de banda”

    O app em si eu gosto e recomendo

    • Eu também gosto do app, mas este texto soa como pedir ao ChatGPT para criar uma peça de marketing diferente. No geral, não faz muito sentido, ainda mais para quem já passou por um ataque DDoS real
    • Eu gostaria que aparecesse ainda mais esse ponto de “se gabar de como o deploy é simples”. Quanto mais as pessoas perceberem que sua infraestrutura excessivamente complexa não é o ideal, melhor
  • Isso parece menos um ataque DDoS e mais, pela descrição, cerca de 8 TB por mês de tráfego adicional que se aproxima de um “abuso de serviço irritante e sem sentido”
    Não há problema em ignorar esse tipo de abuso enquanto ele não causar custo ou esgotamento de recursos, mas histórias como “descobrimos que 80% da capacidade da frota de autoscaling não fazia nada útil” são deprimentemente comuns, então é preciso pelo menos ficar de olho

    A parte mais irritante desse tipo de abuso costuma ser os logs. A maior parte dos logs fica preenchida pelos mesmos hosts repetindo as mesmas ações inúteis. Se o armazenamento de logs for barato e abundante, não é um grande problema, mas ter uma forma de classificar automaticamente certo tráfego como abuso e suprimir o processamento rotineiro é definitivamente uma boa ideia

    Só que não é tão fácil quanto parece. Perdi a conta de quantas vezes adicionei lógica de classificação para capturar abusos óbvios e idiotas em servidores SMTP de entrada, e toda vez ela acabava pegando também cenários limítrofes que eram válidos

    Se você passa tempo demais em uma sequência de tocas de coelho, fica fácil não conseguir fazer o trabalho de verdade. Por isso, às vezes é melhor terceirizar; ou, se isso também for trabalhoso ou caro demais, simplesmente ignorar o abuso mesmo sendo irritante

    • Na AWS, 8 TB de tráfego de saída custam 595 dólares mesmo considerando 1 TB gratuito por mês; na Hetzner, começam em menos de 10 dólares
      Na DigitalOcean, por exemplo, no s-4vcpu-8gb-intel, você paga 30 dólares pelos 3 TB excedentes acima dos 5 TB incluídos, e na Linode o excedente de 3 TB custa 15 dólares. Então acho que o texto tem um ponto
    • Se você continuar ignorando, acaba incentivando a fazerem coisas ainda mais suspeitas. Foi esse tipo de atitude que transformou a internet de hoje quase em um pântano
  • Isto não é um “ataque” digno de nota. Um único script bash disparado sem controle na máquina de alguém já conseguiria fazer isso
    “50 milhões de requisições por mês no Reino Unido” dá, em média, menos de 20 requisições por segundo. Eu esperaria que um único servidor Go desse conta de 250 vezes esse volume de requisições sem grandes otimizações

    O conselho em si não é necessariamente ruim, mas esses números não servem como prova do conselho. Para um serviço de API HTTP em Go, eu esperaria que um VPS pequeno a médio lidasse com 5 mil requisições por segundo sem otimização, mesmo com algum trabalho de banco de dados e formatação JSON. É um número baseado na experiência de ter implantado dezenas de serviços parecidos em um lugar que recebia bilhões de requisições por dia e, nos picos, passava de 500 mil requisições por segundo

    • Se esse tráfego chega à API como requisições repetidas e vem todo de locais que não parecem suspeitos, antes de pensar em DDoS eu consideraria a hipótese de alguém ter colocado por engano um loop infinito de novas tentativas no código do cliente
  • É bom que isso não esteja causando dano, mas me deixa um pouco inquieto tomar isso como conselho, porque falta muita coisa
    Preferir distribuir binários em vez de Docker é ok, mas o que fazer com o host onde esse binário roda? Um dos motivos para usar contêineres é empacotar as configurações de reforço de segurança junto com a implantação, para ter certeza de que, quando for preciso escalar depois, as configurações de segurança serão iguais entre os nós

    O monólito mencionado aqui pode ser colocado em um único VPS, e isso é bom e barato. Mas, se ele travar ou se o hardware falhar por qualquer motivo, pode haver um tempo de indisponibilidade considerável

    Outra preocupação é que, ao juntar tudo em um monólito, você perde a defesa em profundidade da pilha da aplicação. Se alguém invadir a aplicação pelo frontend, pode ir direto até o armazenamento de dados do backend. É por isso que muita gente coloca o armazenamento de dados atrás de serviços web internos e o isola com grupos de segurança em uma rede privada separada do frontend, limitando a superfície de ataque ao nível das ações que podem ser executadas pelo navegador

    • Não existe mundo em que aumentar a superfície de ataque melhore a segurança

    • Se você acha que instalar Docker deixa o host seguro, está enganado. Como você vai configurar hosts adicionais quando escalar?

      Ao usar Docker, não basta proteger os contêineres; o host também precisa estar seguro, inclusive o serviço que executa os contêineres. Ao escalar e implantar hosts adicionais, eles precisam estar igualmente seguros

      Se você usa infraestrutura como código e configuração como código, não há diferença essencial entre implantar um binário por trás da configuração do sistema ou implantar Docker

    • Existem ferramentas para tornar uma configuração “bare metal” reproduzível em algum grau. Por exemplo, NixOS, Ansible e builds de imagens Amazon AMI

    • Nunca entendi bem a expressão “invadir a aplicação pelo frontend”. Injeção de SQL mexe diretamente no armazenamento de dados sem execução remota de código, e XSS afeta outros usuários lateralmente
      Então como exatamente alguém sai do frontend e chega livremente a todo o backend? As pessoas estão rodando um interpretador JavaScript com acesso a shell dentro de serviços de API em Go e chamando eval em entradas de usuário? Tecnicamente, isso me parece muito forçado

    • No fim, isso não é segurança por obscuridade? Algo como tornar tudo tão complexo que, se nem nós entendermos, os outros também não vão entender?

      O importante não é criar mais paredes, e sim fazer com que as paredes não possam ser derrubadas. Interfaces reduzem desempenho e aumentam complexidade

  • Pessoalmente, essa expressão me incomoda. “1 bilhão de requisições por mês” dá aproximadamente 370 requisições por segundo. É um nível que um único servidor bem configurado consegue atender e, com certeza, menos de 10 servidores bastariam
    Um único script bash malicioso também consegue gerar esse volume de tráfego

    • Graças aos microsserviços, precisamos de 45 nós Kubernetes para lidar com 1000 requisições por segundo
    • Isso se essas requisições estiverem distribuídas uniformemente ao longo do tempo. Mas, em uma situação de ataque, as requisições podem disparar de repente e depois estabilizar, e ainda assim somar 1 bilhão de requisições no mês considerando 30 dias
    • Não é nem um servidor bem configurado: depois que o JVM JIT entra em ação, um único core já consegue
  • Talvez eu esteja sem senso de realidade, mas dezenas de bilhões de requisições por mês não parecem grande coisa. Isso é considerado um grande ataque DDoS?

    • Depende de quem paga a conta. Se for hospedagem própria, não é problema, mas em serverless esse nível costuma sair caro, especialmente se for tráfego sem valor
    • Para uma API projetada de forma razoável, 300 a 400 requisições de API por segundo não são uma carga pesada. 300 a 400 requisições de arquivos estáticos por segundo é menos que troco de pinga
    • Sim. 1 bilhão de requisições por mês dá em média 380 requisições por segundo, então não é tão alto
    • Depende de vários fatores. Em geral, a infraestrutura é provisionada para o uso esperado, e capacidade ociosa em excesso é desperdício
  • Gostei da parte: “para cada app, criar um serviço monolítico fácil de implantar e manter. Nada de Docker, nada de Kubernetes, nada de dependências, nada de ambiente de runtime; apenas um arquivo binário que pode ser implantado em qualquer VPS recém-criado”

    • Não uso TablePlus diretamente. Se isso é sobre o site de marketing, é óbvio que Kubernetes não é necessário
      Se é sobre a aplicação, acho estranho dizer que não há dependências. Ela não armazena dados nem gera logs?

    • Essa é uma vantagem realmente excelente do Golang. Você sobe um VPS, aplica padrões razoáveis, compila de forma cruzada e executa o binário

      Comparado a deploys em Python, Node e PHP, há muito menos complexidade desnecessária

      Seria ótimo se executar e manter um servidor de banco de dados vivo também pudesse ser tão simples

  • Pelo título, eu esperava algo mais no estilo swole doge. Concordo com boa parte dos conselhos, mas estar atrás da Cloudflare está longe de ser “nada”
    Dependendo da distribuição do tráfego, talvez um VPS sozinho sem Cloudflare também tivesse aguentado bem, e a escala nem parece tão grande assim. Teria sido interessante ver estatísticas mais detalhadas, como requisições por segundo e quanto a Cloudflare bloqueou antes de chegar à origem

    Um DDoS de camada 7 vindo da Rússia contra empresas suecas que eu conheço foi grande o bastante para derrubar grandes provedores por problemas de capacidade. Isso incluiu Verizon, Azure Frontdoor, Cloudflare e balanceadores de carga do GCP. Contra uma escala dessas, essa estratégia definitivamente não funcionaria