Pourquoi TablePlus n’a rien fait face à des tentatives de DDoS qui durent depuis plusieurs semaines
(tableplus.com)- Malgré des tentatives de DDoS qui durent depuis plusieurs semaines, TablePlus se contente d’observer l’état de ses serveurs, sans blocage d’IP ni mode Cloudflare « Under Attack »
- Les tentatives de téléchargement des fichiers d’installation ont atteint environ 6 millions sur les 30 derniers jours, dont 800 126 sur les 5 derniers jours, pour des fichiers d’environ 200 MB par téléchargement
- Même pendant l’attaque, l’utilisation CPU des serveurs est restée la plupart du temps entre 0 et 1 %, avec une architecture capable de traiter des dizaines de milliards de requêtes par mois via environ 8 services API et des bases de données sans cache
- Le backend est organisé en services monolithiques par application, déployés sur un nouveau VPS sous forme de binaire unique, sans Docker, Kubernetes ni environnement d’exécution spécifique
- Une pile simple — frameworks Go/Rust, indexation de base de données, séparation de la base de logs, reverse proxy Nginx, Cloudflare CDN/R2, throttling des envois d’e-mails — réduit le coût des attaques et la complexité opérationnelle
Des tentatives de DDoS qui durent depuis plusieurs semaines
- Quelqu’un envoie depuis plusieurs semaines des centaines de millions de requêtes aux serveurs de TablePlus et tente de télécharger les fichiers d’installation des millions de fois
- Les tentatives de téléchargement des fichiers d’installation ont atteint 800 126 sur les 5 derniers jours, et environ 6 millions sur les 30 derniers jours
- Chaque fichier d’installation pèse environ 200 MB
- D’après les appels API des 30 derniers jours, la majorité du trafic provient de l’UE, en particulier d’Allemagne et du Royaume-Uni
- Ces chiffres n’incluent ni les requêtes de téléchargement ni le trafic CDN
- L’attaque était toujours en cours au moment de la rédaction
La réponse réelle : tenir sans bloquer
- Les adresses IP des attaquants ne sont pas bloquées
- TablePlus utilise Cloudflare, mais n’active pas le mode « Under Attack »
- Même pendant l’attaque, le CPU des serveurs reste la plupart du temps à 0–1 %, donc pratiquement inactif
- Comme le service peut absorber sans problème des dizaines de milliards de requêtes par mois et que le coût reste limité, presque aucune mesure spécifique n’est prise
Une conception backend simple
- L’architecture de TablePlus privilégie la simplicité, et les services backend sont eux aussi maintenus dans une configuration minimale autant que possible
- Les services de rendu tiers comme Vercel ou Netlify ne sont pas utilisés, car ils peuvent devenir un goulot d’étranglement en cas d’attaque ou générer des factures imprévues
- L’équipe considère qu’utiliser son propre serveur web permet d’éviter ces limites
- Par le passé, un monolithe pouvait devenir un goulot d’étranglement à cause de VPS et de processeurs peu puissants, mais les VPS actuels offrent des CPU multicœurs, beaucoup de RAM et des SSD rapides
- Les SSD rapides et la RAM améliorent fortement les performances des bases de données
- S’il est correctement implémenté, un service monolithique sur une seule instance peut lui aussi traiter des dizaines de milliards de requêtes par mois
Fonctionnement du monolithe par application
- Pour chaque application, l’API, le site web, les e-mails, les paiements, etc. sont regroupés dans un seul service
- Le déploiement se limite à un fichier de configuration, une phase de build, puis un déploiement
- Cela permet de migrer rapidement le service vers un autre fournisseur cloud ou de le redéployer
- Avec peu de dépendances, il est plus facile de déboguer et d’identifier les goulots d’étranglement
- Même en cas d’erreur, il n’y a qu’un ou quelques services à inspecter
- Exemples de frameworks monolithiques possibles
- Golang : Echo, Gin
- PHP : Laravel
- Ruby : Rails
- Rust : Actix, Rocket, Warp
Principes d’architecture pour des dizaines de milliards de requêtes par mois
- Choisir un framework web haute performance ; TablePlus privilégie Golang et Rust
- Ajouter des index dans la base de données pour réduire les temps de requête à mesure que le volume de données augmente
- Séparer la base principale de la base de logs et de données d’usage afin de protéger les performances du cœur métier
- La base principale sert aux données qui ne changent pas, ou dont la taille n’augmente pas avec le temps
- La base de logs et d’usage sert aux données qui continuent de grossir au fil du temps
- Placer un reverse proxy devant les API critiques pour traiter et répartir les requêtes
- Cela aide lorsqu’il faut plusieurs serveurs
- TablePlus utilise Nginx
- Tout placer derrière Cloudflare, avec une configuration adaptée du cache, d’Argo et du full SSL entre Cloudflare et les serveurs
- Utiliser un CDN avec protection DDoS
- Pour réduire les coûts et améliorer la protection, TablePlus préfère Cloudflare R2 et le CDN à Amazon CloudFront + S3
- Héberger de gros fichiers de téléchargement sur un VPS sans CDN ni cache épuise rapidement la bande passante
- TablePlus utilise le CDN Cloudflare à bande passante illimitée
- Si Argo est activé sur le même domaine, le trafic du CDN Cloudflare peut passer par Argo, et comme la bande passante Argo n’est pas gratuite, les coûts peuvent fortement augmenter
- Pour les requêtes qui doivent envoyer des e-mails depuis le serveur, comme la récupération de mot de passe, un throttling protège le service de messagerie
Déploiement : exécuter des binaires sans conteneurs
- TablePlus garde un processus de déploiement aussi simple que possible, sans Docker, Kubernetes, conteneurs ni configuration d’environnement d’exécution séparée
- L’unité de déploiement est le binaire
- Il est copié sur un serveur Linux puis exécuté comme un processus
- L’approche est similaire à l’exécution de l’application TablePlus sur macOS
- On peut confier à Linux Systemctl la supervision du processus et son redémarrage en cas d’erreur fatale
- L’exécution native est privilégiée afin de ne pas gaspiller CPU et RAM dans des couches intermédiaires comme les VM, la virtualisation ou des gestionnaires d’infrastructure tiers
- Go et Rust sont choisis car ce sont des langages hautes performances capables de produire des binaires prêts au déploiement
Protections à activer en cas d’usage de Vercel
- Vercel propose des fonctions pour protéger un site dans ce type de situation : Spend Management et Attack Challenge Mode
- Spend Management : permet de définir un plafond de dépenses soft ou hard
- Attack Challenge Mode : similaire au mode « Under Attack » de Cloudflare
- Si l’on utilise Vercel, il est nécessaire d’activer ces fonctions
1 commentaires
Avis sur Hacker News
Cet article donne vraiment l’impression d’un auto-congratulation excessive. « 1 milliard de requêtes par mois », ce n’est que quelques centaines de requêtes par seconde, donc c’est dérisoire, et difficile à qualifier de DDoS
En plus, le site est derrière Cloudflare, un CDN, donc je comprends encore moins pourquoi on devrait y voir quelque chose d’impressionnant du point de vue des performances
Par exemple, il n’y a pas de scénario raisonnable où un fichier de 200 Mo ne serait pas mis en cache et servi par le CDN. Il n’y a pas de quoi être fier du fait que le serveur applicatif ne lise pas 200 Mo depuis le disque à chaque téléchargement pour les recopier vers le client ; faire ça serait une conception manifestement très mauvaise
Si le fichier de 200 Mo en question est le téléchargement de l’application cliente TablePlus sur https://tableplus.com/download, la version Windows fait 183 Mo et elle est bien mise en cache par 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: 2980N’est-ce pas typiquement le genre de chose dont on dirait qu’il faut plus de 1 000 développeurs dans une boîte FAANG ? Je ne vois pas comment on peut réduire ça à de l’auto-congratulation, alors que de grandes entreprises échouent régulièrement à faire ce genre de choses
C’est difficile de ne voir ça que comme quelques centaines de requêtes par seconde. La densité des requêtes n’est pas uniforme dans le temps, et elle peut souvent monter jusqu’à 20 fois la moyenne
4 To par mois, ce n’est pas vraiment une attaque DDoS, non ? 4 To par heure, là oui, on pourrait parler de DDoS, mais 4 To par mois, ce n’est que 1,5 Mo par seconde
6 millions de requêtes par mois, ce n’est aussi que 2 requêtes par seconde. À cette échelle, le fait que le service tourne en monolithe ne semble pas très important, surtout si l’on considère que Cloudflare traite la plupart des requêtes via son cache CDN
L’immense majorité du Web, ce sont des sites WordPress sur de l’hébergement mutualisé à 5–20 dollars par mois, et quand l’organisation est plus grosse, c’est souvent du Drupal. Sans cache installé, directement branchés à la base de données, la plupart des sites sur Internet peuvent tomber avec seulement 4 requêtes par seconde
Ça peut sembler délirant, mais c’est la réalité. J’ai autrefois géré chez Cloudflare des projets de protection DDoS, WAF, pare-feu et sécurité client, et j’ai souvent vu des sites de clients tomber à cause de scraping Web ou de taux de requêtes HTTP très faibles et tout à fait triviaux
Les gros chiffres font les gros titres, mais ce que la plupart des gens ressentent réellement, ce sont les petits chiffres
Une attaque par déni de service peut se faire avec seulement quelques Ko par heure. Si elle touche un endpoint d’API lourd du service ciblé, cela peut suffire à le faire tomber ; « Distributed » signifie seulement que plusieurs machines attaquent en même temps
Un DDoS n’a pas forcément besoin d’un débit gigantesque. Simplement, ceux dont parlent les news sont généralement les grosses attaques
L’objectif de ce genre d’attaque peut être de brûler le quota de bande passante du serveur d’origine, ou de rendre les coûts de bande passante impossibles à absorber. C’est faisable à très bas coût avec une seule machine d’attaque, ou un petit nombre. La plupart des datacenters et hébergeurs ont des limites de bande passante ou facturent au-delà d’un certain volume, et trop souvent les entreprises attaquées ne s’en rendent compte qu’après avoir reçu une facture ingérable
J’ai un site de téléchargement de jeux avec environ 50 joueurs au total. Personne ne l’utilise, et je dirais que de vraies personnes téléchargent le jeu quelques fois par mois
Pourtant, un seul fichier zip de 2 Go a généré 5 To de trafic le mois dernier, et ça dure depuis des années. Ce n’est pas un DDoS, juste un bot/crawler mal configuré qui suit tous les liens et ne parvient pas à annuler les téléchargements
On dirait plutôt 1 To par jour, mais cela reste malgré tout très faible
Ça dépend probablement du degré d’irrégularité du trafic
Ce n’est qu’un site marketing statique pour une application desktop. Il n’y a pas de forum de discussion, et les retours passent par des issues GitHub
Se vanter de la simplicité du déploiement d’un site marketing statique, et du fait que des fichiers statiques tiennent le coup même téléchargés des millions de fois par jour, c’est assez étrange. Et ici, c’est Cloudflare qui fait l’atténuation, pas eux. À supposer qu’un si petit trafic ait besoin d’atténuation
Si j’avais subi ce genre « d’attaque », je ne l’aurais sans doute même pas remarqué avant de recevoir l’e-mail mensuel de Cloudflare disant « X To transférés, presque 100 % de bande passante économisée »
L’application elle-même me plaît et je peux la recommander
D’après la description, cela ressemble moins à une attaque DDoS qu’à environ 8 To de trafic supplémentaire par mois relevant plutôt d’un « abus de service inutile et agaçant »
Tant que ce genre d’abus ne crée pas de problème de coût ou d’épuisement des ressources, on peut l’ignorer, mais les histoires du type « en fait, 80 % de la capacité de notre flotte autoscalée ne faisait rien d’utile » sont malheureusement fréquentes, donc il faut au moins surveiller
Dans ce type d’abus, la partie la plus pénible, ce sont surtout les logs. La plupart des logs se remplissent des mêmes hôtes répétant les mêmes actions dépourvues de sens. Si le stockage des logs est bon marché et généreux, ce n’est pas un énorme problème, mais disposer d’un moyen de classer automatiquement un certain trafic comme abusif et d’en supprimer le traitement habituel est clairement une bonne idée
Cela dit, c’est plus facile à dire qu’à faire. Je ne compte plus le nombre de fois où j’ai ajouté à des serveurs SMTP entrants une logique de classification pour repérer des abus manifestes et stupides ; à chaque fois, cela attrapait aussi des scénarios à la limite mais valides
Si l’on passe trop de temps à enchaîner les terriers de lapin, on finit facilement par ne plus faire le vrai travail. C’est pourquoi il vaut parfois mieux externaliser, ou, si c’est trop pénible ou trop cher, simplement ignorer l’abus malgré l’agacement
DigitalOcean, par exemple, facture 30 dollars pour 3 To au-delà des 5 To inclus avec un s-4vcpu-8gb-intel, et Linode facture 15 dollars pour 3 To supplémentaires. Donc je pense que l’article a quand même un fond pertinent
Ce n’est pas une « attaque » notable. Un simple script bash parti en vrille sur la machine de quelqu’un suffirait à produire ça
« 50 millions de requêtes par mois depuis le Royaume-Uni », c’est en moyenne moins de 20 requêtes par seconde. On s’attendrait à ce qu’un seul serveur Go puisse encaisser 250 fois ce volume sans grande optimisation
Le conseil en lui-même n’est pas forcément mauvais, mais ces chiffres ne constituent pas une preuve en sa faveur. Pour un service d’API HTTP en Go, on s’attend à 5 000 requêtes par seconde sans optimisation sur un petit à moyen VPS, même avec un peu de travail en base de données et de formatage JSON. C’est basé sur mon expérience du déploiement de dizaines de services similaires dans un environnement recevant des milliards de requêtes par jour, avec des pics dépassant 500 000 requêtes par seconde
C’est bien que ça ne cause pas de dégâts, mais il manque trop d’éléments pour en faire un conseil, et ça me met un peu mal à l’aise
Préférer le déploiement de binaires à Docker, pourquoi pas, mais que fait-on de l’hôte sur lequel tourne ce binaire ? L’une des raisons d’utiliser des conteneurs est d’embarquer les réglages de durcissement de sécurité avec le déploiement, afin d’avoir la certitude que, lorsqu’il faudra scaler plus tard, la configuration de sécurité sera identique entre les nœuds
Le monolithe décrit ici peut tenir sur un seul VPS, ce qui est bien et peu coûteux. Mais s’il crashe ou si le matériel tombe en panne pour une raison quelconque, le downtime peut être assez important
Une autre inquiétude, c’est qu’en regroupant tout dans un monolithe, on perd la défense en profondeur dans la stack applicative. Si quelqu’un compromet l’application via le frontend, il peut aller directement jusqu’au stockage de données backend. C’est pour cela que beaucoup de gens placent le stockage de données derrière un service web interne, protégé par des groupes de sécurité sur un réseau privé séparé du frontend, afin de limiter la surface d’attaque aux actions réalisables depuis le navigateur
Il n’existe aucun monde où augmenter la surface d’attaque améliore la sécurité
Si vous pensez qu’installer Docker sécurise l’hôte, c’est faux. Quand vous scalez, comment allez-vous configurer les hôtes supplémentaires ?
Avec Docker, il faut sécuriser non seulement les conteneurs, mais aussi l’hôte, c’est-à-dire le service qui exécute les conteneurs. Et lorsque vous scalez et déployez des hôtes supplémentaires, ils doivent être sécurisés de la même manière
Si vous utilisez de l’infrastructure as code et de la configuration as code, déployer un binaire derrière une configuration système ou déployer Docker ne change pas fondamentalement grand-chose
Il existe des outils qui rendent les configurations « bare metal » assez reproductibles. Par exemple NixOS, Ansible ou la construction d’images Amazon AMI
Je ne comprends jamais vraiment l’expression « compromettre l’app via le frontend ». L’injection SQL touche directement le stockage de données sans exécution de code à distance, et le XSS affecte les autres utilisateurs horizontalement
Mais comment passe-t-on librement du frontend à tout le backend ? Les gens font-ils tourner dans leurs services d’API Go un interpréteur JavaScript avec accès au shell, puis appellent-ils
evalsur les entrées utilisateur ? Techniquement, ça me paraît très tiré par les cheveuxAu final, n’est-ce pas de la sécurité par l’obscurité ? Le raisonnement serait : si on rend ça tellement complexe que nous-mêmes ne le comprenons pas, les autres ne le comprendront pas non plus ?
L’important n’est pas de construire davantage de murs, mais de rendre les murs impossibles à casser. Les interfaces diminuent les performances et augmentent la complexité
Personnellement, cette formulation me gêne. « 1 milliard de requêtes par mois », c’est environ 370 requêtes par seconde. C’est un niveau qu’un seul serveur bien configuré peut gérer, et certainement moins de 10 serveurs suffisent
Un seul script bash malveillant peut déjà générer ce genre de trafic
Peut-être que j’ai perdu le sens des réalités, mais des milliards de requêtes par mois, ça ne me paraît pas énorme. Est-ce que c’est considéré comme une grosse attaque DDoS ?
J’ai bien aimé le passage : « Pour chaque app, on crée un service monolithique facile à déployer et à maintenir. Pas de Docker, pas de Kubernetes, pas de dépendances, pas d’environnement d’exécution : juste un fichier binaire que l’on peut déployer sur n’importe quel VPS fraîchement créé »
Je n’utilise pas TablePlus moi-même. S’il s’agit du site web marketing, il est évident qu’il n’y a pas besoin de Kubernetes
S’il s’agit de l’application, l’absence de dépendances me surprend. Elle ne stocke pas de données et ne produit pas de logs ?
C’est l’un des très grands atouts de Golang. On lance un VPS, on applique des valeurs par défaut raisonnables, puis on cross-compile et on exécute le binaire
Comparé aux déploiements Python, Node ou PHP, il y a beaucoup moins de complexité inutile
Ce serait bien si lancer un serveur de base de données et le maintenir en vie pouvait être aussi simple
En voyant le titre, je m’attendais à quelque chose de plus digne du swole doge. Je suis d’accord avec une bonne partie des conseils, mais être derrière Cloudflare, ce n’est absolument pas rien
Selon la distribution du trafic, un simple VPS aurait peut-être très bien tenu sans Cloudflare, et l’échelle ne semble pas si énorme. Des statistiques plus détaillées, comme le nombre de requêtes par seconde et la quantité bloquée par Cloudflare avant d’atteindre l’origine, auraient été intéressantes
Une attaque DDoS de couche 7 venue de Russie contre une entreprise suédoise que je connais était assez massive pour faire tomber de grands fournisseurs confrontés à des problèmes de capacité. Verizon, Azure Front Door, Cloudflare et même le load balancer GCP étaient concernés. Face à une telle échelle, cette stratégie ne fonctionnerait absolument pas