Vai al contenuto principale
BlogCalcoloDifesa da un attacco di forza bruta alle API di login

Difesa da un attacco di forza bruta alle API di login

Un simbolo di blocco rosso con il seguente testo: "Difendersi da un attacco di forza bruta alle API di login: Perché tagliare le curve può paralizzarvi".

Ammettiamolo: quando si ha fretta di rispettare una scadenza importante, si tagliano i ponti. La copertura dei test diventa discontinua, il codice non è così DRY e la gestione delle eccezioni viene spedita nel cimitero dei debiti tecnologici, cioè nel backlog. Ci siamo passati tutti.

Ma quando è il momento di tagliare gli angoli, non si deve rinunciare a implementare la salvaguardia del "massimo tentativo di accesso fallito". Se l'API di login non dispone di protezioni adeguate, oggi è relativamente facile accedere a un account utente con la forza bruta.

In questo post vi mostreremo come un aggressore potrebbe forzare un'API di login. Quindi, discuteremo le contromisure che potete adottare per difendere i vostri sistemi.

Un esempio di login API

Per dimostrarlo, abbiamo costruito un server API molto semplice, utilizzando Node.js ed Express. Esso ascolta le richieste POST a un singolo endpoint, /login. Il corpo della richiesta deve avere un username e un password. Se le credenziali sono state fornite con successo, l'API restituisce 200 OK. Altrimenti, restituisce 401 UNAUTHORIZED.

Ecco il codice del nostro semplice server Express:

const express = require('express');
const users = require('./users.json');

const app = express();
const PORT = 3000;

// Middleware to parse JSON bodies
app.use(express.json());

app.post('/login', (req, res) => {
    const { username, password } = req.body;

    // Check if the username exists and the password matches
    if (users[username] && users[username] === password) {
        return res.status(200).send('OK');
    } else {
        return res.status(401).send('UNAUTHORIZED');
    }
});

// Start the server
app.listen(PORT, () => {
    console.log(`Server is listening on port ${PORT}`);
});

Per questa semplice dimostrazione, manteniamo l'elenco dei nomi utente e delle password in un file chiamato users.json.

Abbiamo distribuito il nostro server su un Linode, in ascolto sulla porta 3000. Proviamo a fare una richiesta:

~$ curl -i \        -X POST \        --header "Content-type:application/json" \        --data '{"username":"user08","password":"testpassword"}' \         172.233.153.34:3000/login

HTTP/1.1 401 UnauthorizedX-Powered-By: ExpressContent-Type: text/html; charset=utf-8Content-Length: 12ETag: W/"c-MvHJP5yPj49I/9tX+wGrvHWbTRk"Date: Sat, 25 May 2024 19:17:34 GMTConnection: keep-aliveKeep-Alive: timeout=5
UNAUTHORIZED

La nostra API di accesso è attiva e funzionante!

Ora, se volessimo forzare la nostra API, potremmo scrivere uno script come questo:

#!/bin/sh

API_ENDPOINT="http://172.233.153.34:3000/login"

USERNAME="user5"

echo "Attempting to login at $API_ENDPOINT as \"$USERNAME\""

for i in {1..8}
do
  PASS="password${i}"
  RESULT=$(curl --silent -X POST --header "Content-type:application/json" --data "{\"username\":\"$USERNAME\",\"password\":\"$PASS\"}" $API_ENDPOINT)
  echo "\"$PASS\": $RESULT"

  if [[ $RESULT == 'OK' ]]; then
    echo "!!! Password for \"$USERNAME\" found: \"$PASS\""
    break
  else
    sleep 1
  fi
done

Quando eseguiamo il nostro rudimentale script di forza bruta, il risultato è questo:

$ source bruteforce.sh
Attempting to login at http://172.233.153.34:3000/login as "user5"
"password1": UNAUTHORIZED
"password2": UNAUTHORIZED
"password3": UNAUTHORIZED
"password4": UNAUTHORIZED
"password5": OK
!!! Password for user5 found: "password5"

Un aggressore può davvero indovinare una password?

Abbiamo visto come sia facile scrivere uno script che possa almeno scorrere alcune password per un dato nome utente. Si potrebbe dire: "Ok, questo è un esempio interessante e artificioso. Ma un aggressore può davvero indovinare una password?".

Ecco un elenco delle 10.000 password più comuni. È un buon inizio per qualsiasi aggressore. Pensateci: avete mai incontrato qualcuno che usa "password123" o "qwerty"? Potreste essere voi!

Se un utente malintenzionato conosce alcuni nomi utente del vostro sistema ed esegue uno script per scorrere queste password comuni, potrebbe ottenere un risultato.

Ad ogni tentativo consentito di combinazione di nome utente e password, aumentano le possibilità di violazione di un account.

Si tratta di un classico caso di autenticazione non funzionante, al secondo posto della OWASP Top 10 API Security Risks. Se la vostra applicazione non si protegge adeguatamente contro gli attacchi automatici, siete in cerca di guai. Senza protezioni, gli account degli utenti sono a rischio.

Le password sono spesso l'anello più debole della sicurezza di un sistema:

  • Gli utenti riutilizzano le password su più siti.
  • Gli utenti scelgono password facili da ricordare (e da indovinare).
  • Gli utenti aggiornano raramente le loro password.

Tutti questi fattori rendono gli attacchi a forza bruta spaventosamente efficaci.

Torniamo quindi alla nostra domanda: Un aggressore può davvero indovinare una password? Assolutamente sì. E se non prendete le giuste precauzioni, potrebbe accadere prima di quanto pensiate.

Come posso proteggere la mia API?

Esistono diversi modi per difendersi da un attacco di forza bruta all'API di login.

Stabilire un numero massimo di tentativi di accesso non riusciti.

Impostate un limite al numero di tentativi di accesso non riusciti per ogni utente. Quando si verificano i tentativi di accesso per un utente, tenere un conto corrente dei tentativi di accesso falliti. Se si raggiunge il limite, bloccare temporaneamente l'account o bloccare le richieste successive dall'indirizzo IP del mittente. In questo modo è molto più difficile per un aggressore entrare con la forza bruta.

Utilizzare un firewall per applicazioni web (WAF)

Un WAF può aiutare a proteggere la vostra API rilevando e bloccando le attività dannose.

  • Attività dei bot: Un buon WAF è in grado di distinguere tra utenti legittimi e bot, bloccando gli attacchi brute force automatizzati.
  • Richieste di accesso sospette da dietro Tor: Molti aggressori utilizzano la rete Tor per nascondere la propria identità. Bloccare o contestare le richieste provenienti dai nodi Tor può ridurre il rischio di attacchi.

Haltdos, un WAF disponibile su Linode Marketplace, offre queste e altre protezioni. Integrando questi strumenti, è possibile rafforzare in modo significativo le difese della propria API.

Implementare la limitazione della velocità

Limitare il numero di richieste API da un singolo indirizzo IP in un determinato lasso di tempo. Questo rallenta gli attacchi di forza bruta e li rende meno fattibili. La limitazione della velocità è una buona pratica per tutte le API e gli endpoint, non solo per le API di accesso.

Abilitare l'autenticazione a più fattori (MFA)

Se si aggiunge un ulteriore livello di sicurezza, come l'MFA, si possono vanificare gli attacchi di forza bruta anche quando l'aggressore indovina la password. Per riuscire a superare l'intero flusso di autenticazione, l'utente deve conoscere qualcosa (la password) e possedere qualcosa (un telefono o un token hardware).

Monitoraggio e analisi dei tentativi di accesso

Impostate una soluzione di monitoraggio delle richieste API per tenere d'occhio i tentativi di accesso. Cercate gli schemi che potrebbero indicare un attacco. Questo può aiutarvi a rispondere rapidamente alle attività sospette.

L'implementazione di queste misure può aiutare a proteggere la vostra API da attacchi di forza bruta e a mantenere sicuri gli account dei vostri utenti.

Conclusione

Proteggere l'API di accesso dagli attacchi brute force è fondamentale. Indovinare una password non è così difficile come si potrebbe pensare e automatizzare le ipotesi è un gioco da ragazzi. Il vostro sistema è vulnerabile? Abbiamo illustrato diverse cose che potete fare per proteggere i vostri sistemi. Queste misure miglioreranno in modo significativo la vostra posizione di sicurezza.

Nella frenetica corsa alla creazione di applicazioni e API, vi perdoneremo se taglierete qualche angolo qua e là. Tutti lo fanno. Ma non lasciate le vostre API di login senza protezione! Non aspettate che si verifichi un attacco: agite subito per proteggere il vostro sistema e i vostri utenti. Per una guida più dettagliata sulla registrazione e sul monitoraggio del sistema, consultare i documenti di Linode. Se intendete utilizzare Apache per servire le vostre applicazioni, potete consultare questa guida sulla configurazione di mod_evasive per aiutare il vostro server a sopravvivere agli attacchi DoS/DDoS.

Siate prudenti!

Commenti

Lascia una risposta

Il vostro indirizzo e-mail non sarà pubblicato. I campi obbligatori sono contrassegnati da *