Archivi tag: csrf

Contromisure agli attacchi CSRF

In questo post ho parlato degli attacchi CSRF (Cross Site Request Forgery). Ora vediamo quali sono le possibili contromisure per evitare (o minimizzare) gli effetti nefasti che tale minaccia può provocare.

 

sechttp.jpg

La semplice definizione del metodo HTTP (GET oppure POST) utilizzato per l’invio del contenuto dei form al server non è sufficiente come contromisura. Infatti, se lato server tali variabili non vengono processate nel modo corretto, una richiesta di tipo POST può essere facilmente trasformata in una richiesta di tipo GET, quindi vulnerabile ai CSRF. Nella fattispecie, pur avendo un form simile al seguente:

<form method="post" action="page.php">
<fieldset>
<legend>Inserisci Contatto</legend>
<input type="text" name="nome" id="nome"/>nome:
<input type="text" name="cognome" id="cognome"/>cognome:
<input type="text" name="telefono" id="telefono"/>telefono:
<input type="submit" name="invia" id="invia" value="Invia"/>
</fieldset>
</form>

dove tutti i campi sono obbligatori, lo si potrebbe facilmente tradurre in questa chiamata HTTP GET:

http://www.nomesito.it/page.php?nome=Mario&cognome=Rossi&telefono=06676754&invia=Invia

Quindi, se un attaccante mandasse un’email contenente la suddetta URL alla vittima, e quest’ultima (che ha una sessione attiva su www.nomesito.it) cliccasse sul collegamento, automaticamente verrebbe salvato nel database un record Mario Rossi 06676754.

Pensate a cosa potrebbe succedere se il sito vulnerabile fosse quello di una banca e la URL trappola portasse l’utente vittima ad effettuare (a sua insaputa) un bonifico di N € sul c/c dell’attaccante…

Per fortuna si può correre ai ripari impostando alcuni meccanismi di sicurezza.

Per prima cosa, occorre scindere lato server (ad esempio nel codice PHP) le chiamate HTTP POST dalle chiamate HTTP GET, utilizzando le giuste variabili globali, ovvero $_POST nel primo caso e $_GET nel secondo.

Se si utilizzano la variabile $_POST ed il filtro sul referer HTTP i margini di sicurezza sono buoni (ma non ottimali), in quanto non potrà funzionare la tecnica enunciata in precedenza, ovvero la trasformazione delle chiamate HTTP POST in chiamate HTTP GET e non verranno accettate richieste provenienti da siti esterni.

Se invece si sceglie il GET come metodo di invio dei dati, oppure non si fa una scelta esplicita e si gestiscono i dati diretti al server mediante la variabile globale $_REQUEST (che non fà alcuna distinzione tra GET e POST), allora è assolutamente necessario procedere in questo modo:

1) si crea un stringa random (token);

2) tale token lo si associa automaticamente ad un campo di input hidden (nascosto);

3) si richiede che il valore del suddetto campo hidden sia uguale a quello del token affinchè si possano salvare i dati nel database.

Per intenderci, si potrebbe utilizzare il seguente codice PHP:

session_start();

$token = sha1(time());

$_SESSION['token'] = $token;

session_write_);

nella pagina del login, mentre in tutte le altre pagine il codice sarà:

session_start();

$token = $_SESSION['token'];

session_write_);

if(isset($_REQUEST['invia']))
{
    if(isset($_REQUEST['token']) && $_REQUEST['token'] == $token)
    {
          //invia i dati
    }

    else
    {
          die('Non hai i permessi per visualizzare la pagina');
    }
}

Il campo di input hidden è così definito:

<input type="hidden" name="token" id="token" value="<?php echo $token ?>"/>

Attraverso questa tecnica l’attaccante non potrà conoscere a priori il valore del token e quindi non sarà in grado di “forgiare” una URL malevola. Inoltre, è consigliabile utilizzare tale procedura anche se si utilizza la variabile $_POST, poichè il token è l’unica contromisura quasi infallibile contro gli attacchi in questione.

Un’altro metodo per mitigare i CSRF consiste nella verifica del campo HTTP_REFERER relativo all’header HTTP.

Però, poichè tale controllo è facilmente aggirabile (basti pensare che alcuni browser, tra i quali Firefox, non inviano per default il referer e che tale campo risulta comunque spoofabile, utilizzando ad esempio cULR), solitamente dedico il suo impiego alle sole pagine “riservate” (ovvero accesibili solo dopo autentica da parte dell’utente) che non prevedono l’invio di dati al server.

Il codice PHP è il seguente:

if($_SERVER['HTTP_REFERER'] != '' && !strstr($_SERVER['HTTP_REFERER'], "http://www.nomesito.it"))
{
        die('non hai i permessi per visualizzare la pagina');
}

In soldoni, verifico che il referer HTTP sia vuoto (per non penalizzare utenti legittimi che adoperano un browser che non invia i referer) oppure che contenga il dominio del mio sito, “accertandomi” così che l’utente non provenga da domini “esterni”.

Fine del post, fatene buon uso.

A presto.

Attacco CSRF (Cross Site Request Forgery)

In questo post abbiamo parlato del Cross Site Scripting. Ora ci concentreremo su un altro tipo di attacco Web piuttosto diffuso, ovvero il CSRF (Cross Site Request Forgery). A differenza dell’XSS, la cui logica si basa sulla fiducia riposta dagli utenti su un determinato sito Web, il CSRF si fonda sulla fiducia di un sito Web nei confronti del browser degli utenti. Bhè, mi rendo conto che tale affermazione può risultare un pò criptica, ma lasciatemi spiegare meglio.

Supponiamo che l’utente Bob si sia autenticato sul portale on-line della propria banca, ovvero http://bank.example. Supponiamo inoltre che tale portale salvi le credenziali di accesso all’interno di un cookie e che l’expiration date (la data di scadenza) di quest’ultimo non sia proprio “imminente”. Bob, dopo aver effettuato alcune operazioni sul portale sopra citato (ad esempio controllare il saldo, la lista movimenti, ecc.), continua la navigazione passando da un sito Web all’altro. Accede quindi su un forum che è solito frequentare, clicca su un 3D che ha richiamato la sua attenzione in cui è presente un tag <img> con il seguente attributo: src=”http://bank.example/withdraw?account=bob&amount=10000000&for=Trudy” e, nel momento in cui il suo browser cercherà di caricare l’immagine dall’indirizzo precedentemente menzionato… boom, il danno è fatto. Da notare che la riuscita dell’attacco (e la realizzazione dello stesso), avviene in modo completamente trasparente, sarebbe a dire che la vittima non si accorgerà assolutamente di nulla.

Ma come mai un semplice tag <img> è bastato a far cadere il povero Bob nella trappola tesa da Trudy? Esaminiamo l’indirizzo http://bank.example/withdraw?account=bob&amount=100000&for=Trudy. Possiamo notare la presenza dei caratteri ? e &, classici delle querystring, attraverso le quali gli utenti inviano i dati ai server WEB sfruttando il metodo HTTP GET. Nella fattispecie, viene autorizzata una transazione dal conto dell’utente Bob per un ammontare pari a 100000 $ (o €, fate voi), verso l’utente Trudy, ovvero l’attacker, anche lui cliente della banca di Bob.

Inutile dire che gli effetti potenziali di questo attacco sono completamente imprevedibili (come già detto per l’XSS), anche se, in realtà, l’attuazione del CSRF non è così semplice come può sembrare. Infatti, affinchè tale attacco vada a buona fine, è necessario che vi siano alcune situazioni concomitanti, quali:

1) Il sito a cui punta l’URL malevolo generato dall’attaccante non deve prevedere il controllo del campo referrer presente nell’header HTTP (ovvero verificare il sito di provenienza dei visitatori);

2) L’attaccante deve individuare i giusti parametri da passare al server mediante querystring;

3) La vittima deve essere ancora loggata al sito vulnerabile nel momento in cui l’attacco viene sferrato.

La prevenzione è piuttosto semplice e si basa su alcune regole di buon senso. Ad esempio il sito deve garantire il controllo del referrer, deve consentire la sola autenticazione mediante HTTP POST e GET o, in alternativa, ridurre sensibilmente la durata dei cookie. Inoltre, sarebbe opportuno utilizzare un token (gettone) univoco e pseudocasuale per ogni richiesta HTTP POST effettuata dagli utenti.

Prossimamente analizzeremo alcune varianti del CSRF. A presto.