Indice dei contenuti dell'articolo:
Quando si parla di sicurezza web, uno degli errori più comuni consiste nel progettare le difese osservando il sistema esclusivamente dal punto di vista di chi lo ha sviluppato. Si controlla il codice, si installa un firewall, si aggiunge un CAPTCHA e si presume che il problema sia risolto.
Nella realtà, chi costruisce un bot non guarda l’applicazione come la guardano lo sviluppatore, il sistemista o l’utente finale. Non è interessato all’aspetto grafico della pagina, alla disposizione dei pulsanti o alla qualità dell’esperienza di navigazione. Osserva invece le richieste HTTP, gli endpoint, i parametri, i cookie, i token, le intestazioni e le risposte restituite dal server.
È proprio da questa differenza di prospettiva che nasce una delle lezioni più importanti che abbiamo maturato lavorando ogni giorno con infrastrutture Linux, applicazioni web, servizi gestiti e sistemi esposti pubblicamente: per difendere un’applicazione dai bot bisogna prima comprendere come viene costruito un bot.
Non significa sviluppare strumenti destinati a violare sistemi altrui. Significa studiare, all’interno di ambienti autorizzati e controllati, il modo in cui un software automatico interagisce con un sito, mantiene una sessione, replica una richiesta e tenta di aggirare una protezione.
Un’applicazione pubblica non è mai completamente chiusa
Ogni applicazione accessibile tramite Internet deve comunicare con il dispositivo dell’utente. Il browser invia richieste al server, riceve risposte, scarica risorse, trasmette dati e richiama API. Tutto ciò che deve arrivare al client può essere osservato dal client stesso.
Possiamo minimizzare le informazioni esposte, applicare controlli rigorosi e rendere il processo estremamente complesso, ma non possiamo trasformare una comunicazione pubblica in qualcosa di completamente invisibile.
Un utente sufficientemente motivato può analizzare il traffico generato dal browser e individuare:
- gli indirizzi degli endpoint utilizzati dall’applicazione;
- i parametri inviati nelle richieste;
- le intestazioni HTTP richieste dal backend;
- i cookie necessari a mantenere la sessione;
- la struttura delle risposte JSON;
- l’ordine con cui vengono eseguite le operazioni;
- gli eventuali token utilizzati dal frontend.
Una volta comprese queste informazioni, l’interfaccia grafica può diventare quasi irrilevante. Il bot non ha necessariamente bisogno di aprire la pagina come farebbe un essere umano: può tentare di dialogare direttamente con il backend.
Non possiamo impedire in modo assoluto che un sistema pubblico venga osservato. Possiamo però rendere la sua automazione più difficile, instabile e costosa.
Il problema non è soltanto lo scraping delle pagine
Quando si pronuncia la parola scraping, molti pensano a un programma che scarica il contenuto HTML di alcune pagine per estrarne titoli, prezzi o descrizioni. Questa è soltanto una delle forme possibili di automazione.
Un bot può essere progettato per registrare account, provare credenziali, compilare moduli, interrogare API, prenotare risorse, controllare disponibilità, inviare spam, scaricare file o replicare una parte delle funzionalità offerte da un’applicazione.
Dal punto di vista infrastrutturale, alcune automazioni producono carichi molto evidenti. Generano migliaia di richieste ravvicinate, provengono dallo stesso indirizzo IP e seguono schemi facilmente riconoscibili.
Le automazioni più evolute si comportano diversamente. Distribuiscono le richieste tra più indirizzi, rispettano pause variabili, conservano i cookie, eseguono JavaScript e utilizzano browser reali o browser headless. Possono perfino riprodurre sequenze di navigazione apparentemente credibili.
Per questo motivo il semplice conteggio delle richieste provenienti da un IP non è sufficiente. L’indirizzo IP è un segnale utile, ma non rappresenta necessariamente l’identità di un visitatore. Più utenti legittimi possono condividere lo stesso indirizzo, mentre un singolo operatore automatico può utilizzarne centinaia.
Il CAPTCHA è utile, ma non è una soluzione completa
Quando un modulo viene abusato, la prima reazione è spesso l’inserimento di un CAPTCHA. Si tratta di una scelta comprensibile: introdurre una verifica aggiuntiva può fermare numerosi script elementari e ridurre rapidamente spam e richieste automatiche.
Il problema nasce quando il CAPTCHA viene considerato una garanzia assoluta.
Una verifica di questo tipo rappresenta soltanto uno dei passaggi del processo. Se l’applicazione controlla male il risultato sul backend, accetta token riutilizzabili o protegge il modulo ma non l’endpoint che riceve i dati, il bot può tentare di aggirare l’interfaccia e comunicare direttamente con il server.
Inoltre, un’automazione può utilizzare un browser completo, attendere che la verifica venga superata e proseguire successivamente con le richieste. In alcuni scenari può essere presente persino un essere umano che completa il controllo, mentre il resto delle operazioni viene eseguito automaticamente.
Questo non rende il CAPTCHA inutile. Significa che deve essere inserito in una strategia più ampia, nella quale il backend verifica il token, la relativa scadenza, l’azione per cui è stato emesso e la coerenza con la sessione corrente.
Una protezione lato client che non viene convalidata correttamente lato server è, nella migliore delle ipotesi, un ostacolo temporaneo.
La prima linea di difesa deve essere costruita sul perimetro
Nelle infrastrutture che gestiamo, una parte della protezione viene applicata prima che la richiesta raggiunga direttamente l’applicazione. Servizi come Web Application Firewall, sistemi di rate limiting, analisi della reputazione e strumenti di bot management permettono di ridurre il traffico indesiderato già sul perimetro.
Possiamo, per esempio, applicare limiti differenti agli endpoint di login, registrazione, ricerca o recupero password. Possiamo introdurre verifiche aggiuntive quando una sorgente supera una determinata frequenza, quando presenta caratteristiche anomale o quando tenta ripetutamente la stessa operazione.
È importante evitare configurazioni troppo generiche. Una soglia valida per una pagina di login potrebbe essere completamente sbagliata per un’API utilizzata da un’applicazione mobile o per una pagina che carica numerose risorse in parallelo.
La protezione deve quindi essere contestuale. Non conta soltanto quante richieste vengono inviate, ma anche quale risorsa viene richiesta, in quale sequenza, con quali credenziali e con quale risultato.
Il perimetro può rallentare notevolmente un bot, ma non deve essere l’unico livello di sicurezza. Se l’applicazione accetta qualsiasi richiesta formalmente corretta, un’automazione abbastanza sofisticata potrebbe continuare a operare a velocità inferiore.
La protezione deve proseguire all’interno dell’applicazione
Una difesa più robusta richiede che il backend non si limiti a verificare la presenza dei parametri attesi. Deve controllare anche il contesto nel quale quei parametri sono stati generati.
In un flusso sensibile possiamo utilizzare token firmati, valori casuali non prevedibili e identificatori validi soltanto per un periodo limitato. Questi elementi possono essere associati alla sessione, all’utente, all’azione richiesta o a una specifica fase del processo.
Quando il server riceve la richiesta, dovrebbe verificare almeno che:
- il token sia stato realmente generato dal backend;
- non sia scaduto;
- non sia già stato utilizzato;
- sia collegato alla sessione corretta;
- sia valido per l’operazione richiesta;
- la sequenza delle operazioni sia coerente.
In questo modo non basta copiare una singola richiesta osservata nel browser. Il bot deve ricostruire l’intero processo, mantenere correttamente lo stato e ottenere nuovi valori a ogni tentativo.
È possibile rendere dinamici alcuni elementi del modulo, inserire determinati campi soltanto dopo l’esecuzione di una verifica JavaScript o modificare periodicamente la struttura delle richieste. Queste tecniche possono aumentare il costo dell’automazione, ma non devono sostituire la validazione server-side.
L’offuscamento del codice JavaScript, da solo, non è una misura di sicurezza definitiva. Il codice destinato al browser deve comunque essere scaricato ed eseguito. Può essere reso più difficile da analizzare, ma non può essere considerato segreto.
La decisione finale deve sempre appartenere al server.
Costruire un bot di test cambia il modo di progettare la difesa
Quando analizziamo la sicurezza di un flusso applicativo, cerchiamo di osservarlo anche dal punto di vista dell’automazione. All’interno di sistemi di nostra proprietà o per i quali abbiamo ricevuto un’autorizzazione esplicita, possiamo costruire client di test che simulano differenti livelli di complessità.
Il primo livello può essere un semplice client HTTP che invia richieste senza eseguire JavaScript. Il secondo può gestire cookie, redirect, token e sessioni. Un livello successivo può utilizzare un browser automatizzato e riprodurre una navigazione più simile a quella reale.
Questo approccio permette di rispondere a domande molto concrete:
- l’endpoint può essere richiamato senza visitare la pagina?
- un token può essere riutilizzato più volte?
- la verifica è realmente associata alla sessione?
- la sequenza delle operazioni viene controllata?
- il sistema distingue un errore occasionale da centinaia di tentativi?
- una limitazione può essere aggirata cambiando semplicemente indirizzo IP?
Senza questo tipo di prova, il rischio è realizzare protezioni teoricamente corrette ma praticamente inefficaci. Vedere il proprio sistema funzionare attraverso un client non ufficiale evidenzia immediatamente quali informazioni sono realmente necessarie e quali controlli possono essere saltati.
Non esiste un singolo segnale capace di identificare tutti i bot
Un user-agent insolito può essere sospetto, ma può essere modificato. Un indirizzo IP con cattiva reputazione è un’indicazione importante, ma può essere sostituito. L’assenza di JavaScript può rivelare uno script elementare, ma i browser automatizzati sono in grado di eseguirlo.
Perfino il comportamento apparentemente umano non è una garanzia. Pause casuali, movimenti del mouse e sequenze di clic possono essere simulati.
Una strategia efficace combina quindi più informazioni: frequenza delle richieste, continuità della sessione, coerenza delle intestazioni, reputazione della sorgente, risultati delle verifiche JavaScript, errori generati, percorsi di navigazione e comportamento storico.
Il singolo segnale può produrre falsi positivi. La combinazione di più segnali permette invece di assegnare un livello di rischio e scegliere una risposta proporzionata.
Una richiesta moderatamente sospetta potrebbe ricevere una verifica aggiuntiva. Una richiesta altamente anomala potrebbe essere rallentata o bloccata. Un crawler riconosciuto e utile, come quello di un motore di ricerca, potrebbe essere autorizzato.
Lo scopo non è bloccare qualsiasi automazione, ma distinguere quella utile da quella dannosa.
Bloccare troppo può essere dannoso quanto bloccare troppo poco
Una configurazione anti-bot eccessivamente aggressiva può impedire l’accesso agli utenti reali, interrompere integrazioni legittime, bloccare sistemi di monitoraggio o compromettere l’indicizzazione del sito.
Per questo ogni regola deve essere osservata dopo l’attivazione. Bisogna controllare gli eventi generati, le richieste bloccate, le verifiche completate e gli eventuali problemi segnalati dagli utenti.
Le soglie devono essere adattate al traffico reale. Un e-commerce, un portale editoriale, un gestionale e un’API pubblica hanno comportamenti completamente differenti. Copiare la stessa configurazione da un progetto all’altro può causare risultati imprevedibili.
La sicurezza anti-bot non è un interruttore da attivare una volta per tutte. È un processo di osservazione e correzione continua.
L’obiettivo realistico è aumentare il costo dell’attacco
Nessuna protezione può garantire che un’applicazione pubblica non venga mai automatizzata. Un soggetto con tempo, competenze e risorse sufficienti può continuare a studiare il sistema e adattare i propri strumenti.
Questo non significa che le difese siano inutili. Al contrario, il loro valore consiste nel modificare l’equilibrio economico dell’operazione.
Un bot semplice da sviluppare, veloce e stabile può essere conveniente. Se invece richiede browser completi, proxy, frequenti aggiornamenti, gestione complessa delle sessioni e continui interventi manuali, il suo costo cresce rapidamente.
Ogni livello aggiuntivo può ridurre la velocità dell’automazione, aumentarne gli errori e rendere necessaria una manutenzione costante. In molti casi è sufficiente portare il costo dell’abuso oltre il beneficio ottenibile.
Una buona strategia anti-bot non promette l’impossibile: trasforma un’operazione semplice e conveniente in un’attività lenta, fragile e costosa.
Il nostro approccio come Managed Server
In Managed Server S.r.l. affrontiamo questi problemi partendo dall’infrastruttura, ma senza fermarci all’infrastruttura. Server Linux, reverse proxy, CDN, firewall e sistemi di protezione perimetrale sono fondamentali, tuttavia devono dialogare con la logica applicativa.
Una regola di rate limiting non può conoscere da sola il valore commerciale di un’operazione. Un’applicazione, invece, può distinguere una ricerca da un acquisto, un tentativo fallito da un accesso riuscito, un account appena creato da un cliente storico.
Per questo lavoriamo su più livelli: analisi dei log, configurazione del web server, protezione degli endpoint, gestione delle sessioni, osservazione delle anomalie e coordinamento con gli sviluppatori, nonchè l’implementazione di WAF proprietari ed analisi comportamentali.
Il punto di partenza rimane sempre lo stesso: comprendere come il sistema potrebbe essere automatizzato. Solo dopo possiamo decidere quali passaggi proteggere, quali segnali raccogliere e dove introdurre attrito senza penalizzare gli utenti legittimi.
Difendersi significa cambiare prospettiva
Chi progetta un’applicazione tende naturalmente a seguirne il percorso previsto. Chi costruisce un bot cerca invece la strada più breve, più ripetibile e meno costosa.
Imparare a ragionare in questo modo permette di individuare endpoint troppo permissivi, token riutilizzabili, controlli presenti soltanto nel frontend e flussi che il backend non verifica correttamente.
La conoscenza offensiva, esercitata in modo etico e autorizzato, migliora la capacità difensiva. Non perché consenta di realizzare una barriera inviolabile, ma perché aiuta a evitare protezioni puramente decorative.
Nel web tutto ciò che viene trasmesso può essere osservato e, con sufficiente impegno, imitato. Il nostro compito non è nascondere magicamente ciò che deve essere comunicato, ma costruire sistemi nei quali ogni richiesta venga valutata, contestualizzata e verificata.
È questa la differenza tra aggiungere un CAPTCHA e progettare una vera strategia anti-bot. Ed è anche la ragione per cui, prima di tentare di fermare un’automazione, bisogna imparare a comprenderla.