lunedì 9 marzo 2015

A.S. 2014/15 - Relazione di laboratorio: Autenticazione

Utilizzo un file di testo come database chiamato new.db in cui tutte le password sono crittografate per negare l'accesso a tutte le persone che possono accedere al filesystem, i nomi degli utenti sono scritti in chiaro. Questo sistema consente di mantenere le password nascoste anche allo sviluppatore dell'applicazione e utilizza le funzioni crypt per ottenere un hash della password dal quale non si può risalire alla stessa.


La struttura del file di testo è caratterizzata da separatori (* tra utente e password, | tra un record e un altro) che consentono di suddividere i campi che servono per l'autenticazione (nome utente e password), un esempio di questo file potrebbe essere:
pippo*pluto|admin*pwd
In questo esempio, il database ha memorizzato due utenti che hanno i seguenti dati
  1. Nome utente: pippo Password: pluto
  2. Nome utente: admin Password: pwd
L'applicazione è divisa in 5 pagina per convenienza e chiarezza, il loro funzionamento è descritto di seguito:
  • index.php: Acquisisce i dati e consente la creazione di un nuovo utente grazie a javascript.
  • process.php: Visualizza la pagina di download e reindirizza l'utente alla pagina start.php.
  • newUser.php: Inserisce il nuovo utente (non deve essere chiamata come pagina standalone, è gestita da javascript).
  • start.php: Utilizza l'header octect-stream per il download automatico del file.
  • func.php: Descritto sotto.
Le funzioni di gestione del database sono presenti nel file func.php e sono 3:
  • getDBfromFile
  • createNewUser
  • checkUserPass

Ottieni il database dal file


//Apre il file e lo legge
$fl = fopen($filename, "r");
$file = fread($fl, filesize("new.db"));
fclose($fl);

//Lo suddivide nelle stringhe con formato user*pass
$file = explode("|", $file);
 
return $file;
Questa funzione apre il file in modalità di sola lettura, chiama la funzione fread che ha come secondo parametro quanti byte del file vogliamo leggere (in questo caso tanti byte quanto la grandezza del file stesso = tutto il file) e lo chiude.
Avendo ricavato tutto il file, per poterlo utilizzarlo come database, è necessario suddividere tutti i record (che hanno come separatore il carattere '|') come nella riga numero 7.

Creazione nuovo utente

$fl = fopen(DB_FILE, "a");
fwrite($fl, $user."*".crypt($pass)."|");
fclose($fl);
Apre il file in scrittura e mette il puntatore alla fine del file (non sovrascrive eventuali contenuti già presenti). Scrive i dati passati come parametri con lo standard definito sopra e chiude il file. Non ritorna alcun valore.

Controllo nome utente e password

$autenticato = false;

foreach ($db as $userpass) {

 $user_pass = explode("*", $userpass);
 if ( $user_pass[0] == $user && $user_pass[1] == crypt($pass, $user_pass[1]) ) {
  $autenticato=true;
  break;
 }
}

return $autenticato;
Questa funzione scansiona il database con il costrutto for-each (per ogni) che è possibile leggere come: "Per ogni elemento in $db come $userpass". Ogli volta che verrà eseguito un ciclo, $userpass verrà avvalorato con una linea di database.
Su ogni linea vengono fatte le seguenti operazioni:
  • Scomposizione dello standard "nome*password" in array in cui user è in indice 0 e pass è in indice 1
  • Controllo dell nome utente e della password con quelli dati dall'utente
Se il controllo va a buon fine, la variabile viene impostata come true e viene interrotto il ciclo. La variabile stessa sarà il risultato della nostra funzione. Nel controllo stesso vengono comparati gli hash delle password non essendo presenti le password in chiaro nel database.

Note sulla sicurezza

Il sistema usato garantisce la sicurezza e la privacy degli utenti da persone che hanno accesso al filesystem tuttavia le password vengono inviate in chiaro durante la transizione tra index.php (che acquisisce i dati di login) e process.php (che processa le informazioni e visualizza la pagina di download. Per risolvere questo problema è necessario utilizzare il protocollo HTTPS.

Backup

Il PHP è un linguaggio di scripting completo che consente di interagire anche con il sistema operativo a livello di comandi per shell. Per poter inviare un comando al sistema è possibile utilizzare le funzioni exec o system, la principale differenza tra le due è che system visualizza direttamente l'output dello script a schermo in real time mentre exec lo ritorna in una variabile. In questo caso, non essendo utile visualizzare all'utente il risultato del backup o eventuali messaggi di errore, ho utilizzato la funzione exec.
Il processo di backup viene avviato una volta lanciata la pagina process.php con le giuste credenziali grazie alle seguenti righe:
exec("rm dwDir/*.tgz");
exec('tar -cz --exclude "*.tgz" -f dwDir/back.inc ../../*');
Nonostante exec abbia un valore di ritorno, non è utilizzato. Il primo comando consente la rimozione di tutti i vecchi backup creati dall'applicazione mentre il secondo crea il nuovo backup, escludendo tutti i file di backup. Il nome del file sarà back.inc per non permettere il download diretto del file, verrà rinominato una volta chiamata la pagina start.php

Download

Il solo ed unico contenuto della pagina start.php, che viene chimata una volta creato il backup, è il seguente:
header("Content-Type: application/octet-stream");
header('Content-Disposition: attachment; filename=RossettiBack-'.date("dmy").'.tgz');
readfile("dwDir/back.inc");
La prima riga consente di far interpretare al browser i dati che invieremo come uno stream binario, nella seconda riga specifichiamo che si tratta di un "allegato" e rinominiamo il nome: il nome risultante sarà Rossetti-Back[DATA].tgz sostituendo a [DATA] la data del giorno in cui viene scaricato il file, utile per la gestione di eventuali backup multipli.
L'ultima direttiva consente di leggere tutto il file e inviarlo al browser.
Alessandro Rossetti

Nessun commento:

Posta un commento