freeCodeCamp.org Discourse sta collassando a causa di script spammer

Abbiamo iniziato a notare un aumento del carico su Discourse di freeCodeCamp.org il 21 giugno. Il nostro carico medio della CPU è iniziato a crescere fino a rendere l’intero forum non rispondente.

La nostra indagine iniziale

  1. Abbiamo aggiornato Discourse dalla versione Stable all’ultima versione Tests-Passed (Beta), che è raccomandata per ottenere tutte le ultime correzioni delle prestazioni. Non sembrava esserci molta differenza.

  2. Abbiamo rimosso alcuni dei vecchi plugin per aiutare a diagnosticare il problema, e non sembra essere la causa del rallentamento.

  3. Per escludere eventuali configurazioni errate, abbiamo testato con il tema predefinito e controllato i /logs, trovando alcune eccezioni:

    Job exception: could not obtain connection from the pool within 5.000 seconds (awaited 5.006 seconds); all pooled connections were in use

Questo sembra essere dovuto al fatto che l’istanza potrebbe già essere sotto stress a causa di molti job in esecuzione da lungo tempo.

Il contenitore di Discourse (upstream) è in esecuzione su Digital Ocean e sembra essere sotto forte carico su tutti e 6 i vCPU. Attualmente è in esecuzione sulla versione: 2.5.0.beta7

Ulteriore indagine

  1. Questa mattina i nostri moderatori ci hanno informato che c’è stato un aumento significativo del numero di account spam, il che ci ha portato a credere che potesse trattarsi di un attacco mirato.

  2. Per tentare di mitigare il problema, abbiamo messo il forum in modalità sola lettura. Nonostante ciò, il tasso di utilizzo delle risorse rimane piuttosto alto, superiore al 60%.

  3. Da quanto possiamo capire: da quando è iniziato tutto questo, abbiamo registrato un numero inferiore di richieste al secondo e un tasso di richieste correnti più elevato sul nostro proxy:

  1. Il volume di traffico verso The freeCodeCamp Forum - Join the developer community and learn to code for free. non è cambiato significativamente secondo Google Analytics.
  2. Nessuna delle altre applicazioni sullo stesso proxy sembra essere interessata. Il nostro /news e la piattaforma /learn funzionano normalmente.
  3. Abbiamo provato ad aggiungere un ulteriore limite di velocità sul proxy, ma non ha fatto molta differenza, quindi lo abbiamo rimosso (per permettere agli utenti normali di continuare ad accedere al nostro sito).
  4. Abbiamo anche spostato i reindirizzamenti dal vecchio forum.freecodecamp.com lontano dal forum .org, dato che abbiamo notato che il vecchio sottodominio (che non utilizziamo da 2,5 anni) ha registrato un grande picco di traffico a partire da alcuni giorni fa.

Al momento, con circa 400 utenti in tempo reale, le statistiche appaiono così:

Osservazioni sul comportamento degli spammer

Gli spammer sembrano eseguire uno script che crea nuovi account su un’istanza di Discourse, poi attende diversi giorni. Successivamente, questi account diventano improvvisamente attivi. Iniziano a pubblicare nuovi thread con collegamenti a un sito web. (Forse per costruire backlink?)

Alcuni di questi account sono stati creati già a marzo.

Ecco come appare uno dei loro post spam, sebbene esistano molte varianti che collegano a numerosi siti web:

Qualsiasi consiglio sarà benvenuto.

14 Mi Piace

Questo merita molta più attenzione

Grazie mille per la condivisione!

Una delle mie istanze Discourse preferite, freeCodeCamp, si è bloccata negli ultimi due giorni.

5 Mi Piace

Non credo che il problema principale del carico elevato sia causato dagli spammer.
Ecco perché:

L’uso normale di Discourse (senza API) può funzionare solo con browser moderni perché dipende fortemente da JavaScript. Anche Google Analytics utilizza JavaScript per raccogliere varie informazioni sugli utenti (e non ha bisogno del supporto di JavaScript moderno per eseguire il codice di analisi). Se Google Analytics non riesce a rilevare l’attività degli utenti, allora Discourse non dovrebbe essere in grado di fornire il proprio contenuto e le proprie funzionalità.

Ecco una cattura di un bot quando uso una vecchia libreria per browser headless (phantomjs) per accedere al sito Discourse:

E qui invece con una libreria più moderna (puppeteer):

  1. È strano se qualcuno riesce a pubblicare (senza API) risposte su Discourse mentre Google Analytics non riesce a rilevarli.
  2. Di solito, gli spammer usano proxy pubblici per fare cose sporche e penso che il tuo Cloudflare sia abbastanza intelligente da bloccare i “visitatori dannosi” prima che raggiungano davvero la tua applicazione.

Hai notato code di lavori elevate nel processo Sidekiq?

2 Mi Piace

Ciò ignora il fatto che oltre la metà delle persone nelle comunità tecnologiche utilizza qualche tipo di estensione per il blocco degli annunci, che di default blocca sempre Google Analytics.

18 Mi Piace

Incluso il nuovo macOS.

Era solo una voce sgradevole. Vedi sotto.

5 Mi Piace

Akismet è abilitato? Puoi attivare la moderazione per il livello di fiducia 1?

2 Mi Piace

Sì, abbiamo visto i job salire e scendere come parte della mia indagine iniziale. Abbiamo quindi proceduto a revocare tutte le chiavi utente.

Non sembra tuttavia che questo abbia apportato alcun cambiamento alla stabilità.

Stiamo comunque lavorando a stretto contatto con il team di Discourse per risolvere il problema.

5 Mi Piace

Non capisco perché sia strano che ci siano richieste senza che gli analytics basati su JavaScript mostrino nulla.
Lo spammer può utilizzare gli stessi endpoint usati da JavaScript, ma senza JavaScript. Nessun analytics basato su JavaScript verrebbe attivato.

3 Mi Piace

È molto più probabile che si tratti di un’interazione con un plug-in o di una configurazione errata del proxy. Non abbiamo registrato alcun successo da parte di “spammer” sul nostro hosting.

Dato che si tratta di un sito di programmazione, potrebbe anche essere che “programmatori” stiano cercando di fare qualcosa di strano sul forum?

Ma no — gli spammer non sono un problema generalizzato tra le migliaia di siti che ospitiamo.

3 Mi Piace

Sì, sono propenso a pensare che si tratti di un problema di configurazione (un plugin difettoso o un’impostazione di proxy errata) o di qualcuno che sta manipolando il forum.

La seconda opzione è più probabile, considerando tutti i pattern osservati.

Da quanto ho notato, gli account spam sono stati creati nel corso di un lungo periodo e stanno cercando di aggiungere link (per ottenere backlink??) nelle loro biografie, insieme a ogni sorta di stranezze.

Inoltre, potrebbe esserci coinvolto uno scraping, dato che abbiamo messo il sito in sola lettura, configurato una cache sul proxy e attivato il rate limiting. Tuttavia, il consumo di risorse risulta elevato anche sul container upstream.

Tuttavia, non escluderei che la nostra configurazione possa essere problematica: utilizziamo percorsi secondari e Cloudflare sopra il nostro reverse proxy, un’architettura che tradizionalmente non è la più efficiente secondo le raccomandazioni di Discourse.

1 Mi Piace

image

Un 42,5% di furto di risorse è davvero alto, anche se sei tu a causare problemi su quell’hypervisor. A me sembra un caso di “vicino rumoroso”. Se fossi in te, contatterei DO e chiederei di spostare il droplet su un altro hypervisor.

10 Mi Piace

Sono sicuro che probabilmente lo stai già facendo, ma per sicurezza ti suggerirei di monitorare le connessioni TCP/UDP aperte, riassunte per IP, a livello di sistema operativo. Se c’è un carico elevato della CPU, dovrebbe mostrarti un gran numero di connessioni aperte al server web.

C’è qualche pattern strano nel file production.log?

1 Mi Piace
4 Mi Piace

Ciao Quincy @ossia

Facciamo un passo indietro per un momento e analizziamo la situazione da una prospettiva professionale di cybersecurity, senza speculazioni e senza cercare di “arrampicarsi sugli specchi”.

Il concetto chiave in tutte le attività di cybersecurity è la “consapevolezza situazionale”, che in questo caso viene definita “consapevolezza situazionale informatica” (CSA).

Per sapere “cosa sta succedendo” in modo definitivo, è necessario sviluppare la migliore conoscenza situazionale possibile, senza speculazioni o ipotesi. Solo i fatti.

Come si fa?

Beh, molto brevemente:

Beh, molto brevemente:

Lo facciamo fondendo le informazioni provenienti da tutti i nostri sensori; per le applicazioni basate sul web, queste provengono solitamente dai file di log e dai dati di sessione. Non credo (a mente) che Discourse mantenga le informazioni di sessione nel database PG (l’ultima volta che ho controllato non c’era una tabella delle sessioni come in alcune applicazioni web LAMP), ma questo non è assolutamente un problema insormontabile.

Hai quasi tutto ciò di cui hai bisogno nei file di log nginx sia per il tuo reverse proxy esterno al contenitore (ricordo di aver letto in questo argomento che stavi usando nginx come proxy) che per le stesse informazioni di log all'interno del contenitore. In entrambi gli scenari, il file di log si trova qui, nella configurazione standard OOTB:

Ecco un esempio in uno dei nostri setup (esterno al contenitore) per il reverse proxy:

# cd /var/log/nginx
# ls -l 
total 779964
-rw-r----- 1 www-data adm         0 Jun 17 06:25 access.log
-rw-r----- 1 www-data adm 660766201 Jun 25 18:26 access.log.1
-rw-r----- 1 www-data adm 107367317 Jun 17 03:18 access.log.2.gz
-rw-r----- 1 www-data adm  21890638 May 21 03:08 access.log.3.gz
-rw-r----- 1 www-data adm   7414232 May  5 07:26 access.log.4.gz
-rw-r----- 1 www-data adm     63289 Apr 18 09:12 access.log.5.gz
-rw-r----- 1 www-data adm         0 Jun 17 06:25 error.log
-rw-r----- 1 www-data adm    904864 Jun 25 18:19 error.log.1
-rw-r----- 1 www-data adm     96255 Jun 17 03:17 error.log.2.gz
-rw-r----- 1 www-data adm     79065 May 21 02:58 error.log.3.gz
-rw-r----- 1 www-data adm     70799 May  5 06:54 error.log.4.gz
-rw-r----- 1 www-data adm      1977 Apr 18 05:49 error.log.5.gz

Ecco le stesse informazioni di base che vengono registrate all’interno del contenitore Discourse:

# cd /var/discourse/
# ./launcher enter socket
# cd /var/log/nginx
# ls -l
total 215440
-rw-r--r-- 1 www-data www-data  87002396 Jun 25 18:28 access.log
-rw-r--r-- 1 www-data www-data 101014650 Jun 25 08:02 access.log.1
-rw-r--r-- 1 www-data www-data   8217731 Jun 24 08:02 access.log.2.gz
-rw-r--r-- 1 www-data www-data   6972317 Jun 23 07:53 access.log.3.gz
-rw-r--r-- 1 www-data www-data   3136381 Jun 22 07:50 access.log.4.gz
-rw-r--r-- 1 www-data www-data   2661418 Jun 21 07:45 access.log.5.gz
-rw-r--r-- 1 www-data www-data   5098097 Jun 20 07:38 access.log.6.gz
-rw-r--r-- 1 www-data www-data   6461672 Jun 19 07:40 access.log.7.gz
-rw-r--r-- 1 www-data www-data         0 Jun 25 08:02 error.log
-rw-r--r-- 1 www-data www-data         0 Jun 24 08:02 error.log.1
-rw-r--r-- 1 www-data www-data        20 Jun 23 07:53 error.log.2.gz
-rw-r--r-- 1 www-data www-data       254 Jun 23 02:36 error.log.3.gz
-rw-r--r-- 1 www-data www-data        20 Jun 21 07:45 error.log.4.gz
-rw-r--r-- 1 www-data www-data        20 Jun 20 07:38 error.log.5.gz
-rw-r--r-- 1 www-data www-data        20 Jun 19 07:40 error.log.6.gz
-rw-r--r-- 1 www-data www-data       274 Jun 18 15:40 error.log.7.gz

Nota: Le informazioni “nel contenitore” sono disponibili anche dall’esterno del contenitore sul volume condiviso.

Quindi (e per mantenere questa risposta breve), @ossia, quasi tutto ciò di cui hai bisogno per acquisire una conoscenza situazionale di ciò che sta accadendo si trova in questi robusti file di log. Non sono necessarie speculazioni. I dati sono tutti lì.

C’è anche un’ottima quantità di dati aggiuntivi disponibili nei log di Rails; ad esempio, in uno dei nostri setup, ecco il log di produzione di Rails:

tail -f /var/discourse/shared/socket/log/rails/production.log

Il log di Rails contiene anche molte ottime informazioni di registrazione degli utenti, ad esempio:

Started GET "/embed/comments?topic_id=378686" for 73.63.114.60 at 2020-06-25 18:36:15 +0000
Started GET "/embed/comments?topic_id=378686" for 195.184.106.202 at 2020-06-25 18:36:16 +0000
Started GET "/embed/comments?topic_id=378686" for 17.150.212.174 at 2020-06-25 18:36:16 +0000
Started GET "/embed/comments?topic_id=378686" for 76.235.99.73 at 2020-06-25 18:36:18 +0000
Started GET "/embed/comments?topic_id=378686" for 124.253.211.42 at 2020-06-25 18:36:19 +0000
Started GET "/embed/comments?topic_id=378686" for 103.96.30.11 at 2020-06-25 18:36:21 +0000
Started GET "/embed/comments?topic_id=378686" for 72.191.206.59 at 2020-06-25 18:36:22 +0000
Started GET "/embed/comments?topic_id=378686" for 68.252.68.76 at 2020-06-25 18:36:23 +0000
Started GET "/embed/comments?topic_id=378686" for 69.17.252.83 at 2020-06-25 18:36:23 +0000
Started GET "/embed/comments?topic_id=378686" for 98.109.33.230 at 2020-06-25 18:36:24 +0000

Nota: Qui (sopra, come esempio) vediamo gli indirizzi IP dei client che recuperano il codice incorporato di Discourse da un altro server.

Il compito da svolgere....

Tornando al compito da svolgere, il “trucco” è andare oltre le speculazioni e le ipotesi, e dedicarsi al divertente (1) filtraggio/pulizia dei dati, (2) fusione dei dati e (3) analisi dei dati dei tuoi sensori (file di log) per creare (4) la consapevolezza situazionale (SA) di ciò che sta accadendo sul tuo sito.

Per le vecchie applicazioni LAMP, ho effettivamente del codice personalizzato che ho scritto anni fa e che scrive tutte queste informazioni in una tabella del database, eseguendo l’analisi in tempo reale e contando i “colpi” per indirizzo IP (come esempio), così posso vedere rapidamente cosa, chi e da dove sta colpendo il sito, perché serve del codice per eseguire questo tipo di pulizia, filtraggio e fusione dei dati. (Utile durante attacchi DDOS e attività di bot non autorizzati, ad esempio).

Questo non è un problema per te, @ossia, perché sei freeCodeCamp.org, quindi hai sia le conoscenze per trovare ottimi strumenti di analisi dei file di log (ce ne sono molti nel cyberuniverso) e/o creare il tuo codice personalizzato per eseguire l’analisi rapidamente e facilmente in base allo scenario che desideri comprendere (il tuo argomento e il tuo problema).

Ho scritto il mio codice personalizzato per una vecchia applicazione LAMP legacy in poche ore molti anni fa, e non sono affatto un genio della programmazione, anche se a volte vengo definito una “leggenda” da molti nel campo della cybersecurity, LOL :slight_smile:

Per riassumere....

Beh, per riassumere…

Hai tutti i dati necessari per creare una profonda conoscenza situazionale di “cosa sta succedendo” sul tuo sito e puoi creare quella SA pulendo, filtrando, fondendo ed eseguendo un’analisi di base dei dati dei tuoi file di log. Esistono strumenti che possono aiutare, ma trovo sempre più facile scrivere del codice personalizzato in base all’obiettivo dell’analisi (analisi dipendente), YMMV, ma puoi farlo facilmente perché sei freeCodeCamp.org e possiedi molte competenze tecniche.

Ti consiglio di allontanarti dal tentativo di ottenere la SA da Google Analytics e altre applicazioni di terze parti basate su JavaScript. Nulla è migliore dei tuoi stessi file di log web (e dei dati di sessione del DB, se li hai) e non devi preoccuparti di “cosa potrebbe o meno essere bloccato” ecc. I file di log del tuo server web contengono i dati necessari per ottenere la CSA di cui hai bisogno (e possono anche essere personalizzati quando necessario).

In alcuni dei miei codici CSA, intercetto effettivamente le informazioni di sessione e le informazioni di log dalle richieste HTTP non registrate da nginx, apache2 e altri server web (per informazioni aggiuntive); ma non ho ancora scritto questo tipo di codice per Discourse (per ora), poiché non sono un sviluppatore di plugin Discourse “facile come la panna” (come i guru del team di meta Discourse qui) quanto lo sono con le applicazioni LAMP, avendo iniziato con Discourse solo pochi mesi fa e non avendo ancora scritto alcun codice CSA personalizzato per Discourse (e cercando di scrivere meno codice quest’anno, a essere onesti).

La CSA si basa sulla fusione dei dati dei sensori e dalla CSA deriva la conoscenza necessaria per comprendere quali azioni intraprendere per risolvere qualsiasi problema di cybersecurity.

Tanti auguri per la tua ricerca e spero che questo ti aiuti ad avere più riposo :slight_smile:

Saluti!


Riferimento CSA Originale (Storico):

Riferimento CSA Originale (Storico):

https://www.researchgate.net/publication/220420389_Intrusion_Detection_Systems_and_Multisensor_Data_Fusion

(Riferimento solo per le persone interessate alle origini e alla tecnologia di base della CSA)

13 Mi Piace

Grazie per il vostro ottimo lavoro, team!

E grazie così tanto, tanto, tanto
per aver semplificato
quella barra degli strumenti :nauseated_face: doppia

4 Mi Piace

Chiudo semplicemente il cerchio qui.

Discourse ospita ora https://forum.freecodecamp.org/. Il sito è velocissimo e gli script degli spammer non causano nemmeno un minimo rallentamento. Rimane ancora un po’ poco chiaro quale fosse il problema su Digital Ocean: potrebbe esserci stato un “vicino rumoroso”, la macchina potrebbe essere stata sottodimensionata o potrebbero esserci stati guasti hardware. Non ne siamo sicuri. Comunque, il problema originale è ora risolto al 100% e la comunità è molto felice.

16 Mi Piace