Salve a tutti, dovendo gestire la sezione riservata di alcuni siti (e ovviamente anche l'output dei valori passati tramite querystring nella zona pubblica) volevo discutere, se fosse possibile delle tecniche utilizzate da me e da per capire come migliorarci reciprocamente per rendere le nostre applicazioni web davvero sicure.
Login
Si tratta della parte in cui controllo che l'utente sia loggato sul sito o meno.
Nel caso l'utente non sia loggato, nella pagina index.php compare il form di login, nel caso di pagine interne compare un messaggio di errore che invita ad un login rimandando alla index.
codice PHP:
if($varUtente==$auth)
include 'main.php';
else
include 'login.php';
(oppure, se non è la index)
include 'error.php';
A questo punto la domanda è relativa alle due variabili utilizzate:
$auth è una stringa random unica per tutto il sito che funge da "controllore", è definita in un file php del sito e non può essere modificata direttamente.
$varUtente è invece una stringa che è salvata in fase di login. Seguendo questa guida (php.html.it/articoli/leggi/875/sessioni-alternative-in-php/) su un altro sito ho infatti evitato di usare sessioni e/o cookie per l'applicazione, ma la logica è questa:
- Inserisco nick e password
- I dati vengono confrontati nel database con quelli esistenti (dopo essere passati al vaglio delle funzioni di sicurezza, ne parlo più avanti)
- Se il login va a buon fine viene generato un token della durata di 30 minuti (inviato alle pagina successive tramite querystring) il cui valore è salvato nel database insieme alla sua scadenza e ad alcune variabili di controllo (id utente, nickname, livello e variabile $auth in modo da non cercare più dati nella tabella degli utenti).
- Nelle pagine successive recupero il token, controllo che esista nel database, estraggo la variabile utilizzata come "controllo" (che sarebbe quella random usata nel sito), la salvo in $varUtente e controllo che le due coincidano per dare i permessi in entrata.
Vi chiederete perchè faccio così e non imposto una variabile a true se la sessione esiste e non è scaduta: perchè impostando una singola variabile a true e avere quindi qualcosa del tipo
If(sessione_esistente) $var = true
if($var=='true') echo "sei loggato!";
else "non sei loggato";
``` Avevo il timore di scordarmi di dichiarare di base la variabile a false e, nel caso il register_globals fosse settato male, passando tramite querystring un "pagina.php?var=true" un malintenzionato avrebbe avuto l'accesso comunque.
Così le variabili diventano due di cui una sicuramente settata e mi sento più sicuro.
**Hash della password**
Non ho la necessità di recuperarla, quando serve preferisco spedire una mail per fare in modo che ne venga generata una casuale che l'utente cambierà.
codice PHP:
function criptpass ( $pass )
{
$passaggio = md5($pass);
$password_hash = sha1($passaggio.$auth);
return $password_hash;
}
**Eliminazione vulnerabilità XSS e HTML**
Mi duole dirlo ma qui non ho fatto passi da gigante e sono più o meno rimasto al livello dell'altro post. Più che altro per due motivi:
1) Non mi è ancora capitato di usare un editor HTML semplificato. Nel caso l'idea suggeritami era di "eliminare la possibilità di inserire attributi", ma anche questo non è fattibile immediatamente: se dovessi usare un editor nel quale mi è richiesto di usarli (penso ai vari editor come fckeditor o altri che vedo nei CMS)
2) Dato che questa parte è quella che utilizzo anche per filtrare le variabili recuperate tramite GET e POST ho due problemi che tutt'ora devo trovare il tempo di sviluppare:
- Nel caso di array passati tramite GET esiste una funzione (senza riscoprire l'acqua calda) che in maniera ricorsiva mi pulisca tutto (meglio ancora: esiste una funzione che in maniera ricorsiva mi pulisca tutto il mio GET e/o POST?)
- Se al posto di quanto uso adesso (che trovate sotto) usassi qualcosa tipo
trim(addslashes(htmlentities($var))) non otterrei lo stesso risultato in termini di sicurezza?
Io di base faccio così:
codice PHP:
function killHTML($html)
{
$myReg = '/<[^>]?[^>]?>/';
if(preg_match($myReg, $html))
{
$var = preg_replace($myReg, '', $html);
}
else
{
$var = $html;
}
$badHTML = array("<", ">", "//", "/>");
$var = str_replace($badHTML, '_', $var);
return $var;
}
function killXSS($var)
{
$badString = array('<javascript', '<script', '</script', '<iframe', 'onload = ', '<layer', '<meta http', '<object', '</object>', '<input', 'background = ', '<bgsound', '<style', 'http');
$goodString = array('jav-asc-rip-t', '', '', 'fr-a-me', 'onl-oad', 'la-y-er', '', '', '', '', '', '', '', 'ht_tp');
$var = str_replace($badString, $goodString, $var);
foreach($badString as $badWord)
{
if(stristr($var, $badWord))
{
$var = str_replace($badString, $goodString, strtolower($var));
}
}
return $var;
}
function killALL($var)
{
$var = killXSS($var);
$var = killHTML($var);
$var = addslashes($var);
$var = str_replace(chr(13), "<br />", $var);
return $var;
}
**Gestione**
Per gestione intendo il recupero di valori da form e di valori tramite querystring (GET e POST).
Utilizzando le funzioni sopra descritte faccio un semplice $var = (killALL($_GET['valore'])) per eliminare XSS e HTML.
**Domande**
**1)** Domanda personale di cui leggevo questi giorni: è utile in fase di login (quindi quando si devono ricevere nick e password) controllare che la richiesta arrivi effettivamente da una pagina nel nostro server o è pura formalità nel caso di pagina ben studiata e "messa in sicurezza"?
E nel caso, è utile estendere la cosa a tutte le pagine e quindi imporre che la pagina precedente (tranne che per la index) sia una pagina sul nostro server?
**2) **è utile impostare un massimo numero di tentativi per singolo IP (immagino che dopo 3-5 tentativi sia un malintenzionato che tenta di entrare)
Un grazie a chi vorrà discutere di questo spinoso argomento per migliorarci a vicenda :ciauz:.
Spero che il codice condiviso serva a voi e che vogliate condividere le vostre esperienze per il bene di tutti!