- Home
- Categorie
- Coding e Sistemistica
- MYSQL e altri Database
- [Tutorial] La Gestione degli utenti in PHP e MySQL
-
@LowLevel said:
@PaTeR said:
Naturalmente nel caso di una gestione di questo tipo le query che devono essere eseguite sono ben 2 per 'inserimento: una si occuperà di inserire i dati primari dell'utente, l'altra di inserire le informazioni personali. Per ricevere le informazioni l'operazione diventa un pò più complicata, dato che: Prima ci dobbiamo prendere l'ID dell'utente con una SELECT nella tabella "utenti"; Poi facciamo una SELECT nella tabella "info" inserendo l'ID e prendendoci le informazioni di quel determinato utente.
Perché due SELECT separate quando si può fare con una sola?
Aggiungo anche che l'idea di gestire gli ID di sessione col database è ottima, sopratutto per ragioni di sicurezza, tuttavia implementare questa soluzione per poi archiviare in chiaro le password è un po' come sbarrare tutte le finestre di casa lasciando però aperta la porta principale.
Ben vengano gli ID di sessione nel database, ma la stessa scrupolosità e attenzione alla sicurezza dovrebbe imporre l'esclusione di password in chiaro nel database.
Inoltre, quando l'utente inserisce la password nel form, come viene inviata la medesima al server? In chiaro? Non si fa!
E se io scopro in qualche modo l'ID di sessione di un utente e provo a collegarmi al server spedendo quell'ID, come fa il sistema ad evitare di scambiarmi per quell'utente?
Non vorrei aver equivocato le finalità del progetto. Se si tratta di un semplice script per il riconoscimento degli utenti, allora non è il caso di preoccuparsi. Ma se una maggiore sicurezza rientra nelle caratteristiche che si desidera implementare, allora bisogna pensare ad un bel po' di cose oltre a quelle già citate.
Intendi usare Javascript per codificare la password?Comunque fai degli esempi per favore, sinceramente non ci avevo mai pensato a quello che dici tu... Per il momento non ho nessuna idea tranne l'uso di una connessione SSL...
-
Intendi usare Javascript per codificare la password?
Sì. Questo non elimina del tutto il problema ma lo riduce almeno nell'80% dei casi, ad occhio e croce.
Se vuoi, spiego. Ma ti anticipo che sarò costretto a scrivere un bel po' di roba, per spiegare come funziona (il codice finale sarà invece pochissimo), quindi decidi tu se è il caso di introdurre queste caratteristiche al progetto o se queste spiegazioni lo complicherebbero troppo.
-
@LowLevel said:
E se io scopro in qualche modo l'ID di sessione di un utente e provo a collegarmi al server spedendo quell'ID, come fa il sistema ad evitare di scambiarmi per quell'utente?
E' un pò difficile fare una cosa del genere, però credo che in questo caso il sistema penserà che tu sei quell'utente per cui avrai accesso.
Mi sono gia dedicato alla realizzazione dell'autenticazione utente. Però girato e rigirato nell'ID di sessione le password sono in chiaro. Per cui quello che ho fatto io non può essere considerata una soluzione professionale.
-
@LowLevel said:
Perché due SELECT separate quando si può fare con una sola?
Concordo pienamente anche perchè se fai un semplice schema E-R ti accorgi subito che non ha senso avere 2 tabelle.
@LowLevel said:
Aggiungo anche che l'idea di gestire gli ID di sessione col database è ottima, sopratutto per ragioni di sicurezza, tuttavia implementare questa soluzione per poi archiviare in chiaro le password è un po' come sbarrare tutte le finestre di casa lasciando però aperta la porta principale.
Se non sbaglio in MySQL c'è un bel comandino MD5(password) per inserire la pw criptata nel db...
@LowLevel said:
Inoltre, quando l'utente inserisce la password nel form, come viene inviata la medesima al server? In chiaro? Non si fa!
Vero vero...
@LowLevel said:
E se io scopro in qualche modo l'ID di sessione di un utente e provo a collegarmi al server spedendo quell'ID, come fa il sistema ad evitare di scambiarmi per quell'utente?
mmmm, si potrebbe fare il controllo incrociato ip-sessione.
Ossia, arrivo, mi loggo, inserisco sessione e ip nel db e poi ad ogni pagina controllo questa coppia...
sono ?@LowLevel said:
Non vorrei aver equivocato le finalità del progetto. Se si tratta di un semplice script per il riconoscimento degli utenti, allora non è il caso di preoccuparsi. Ma se una maggiore sicurezza rientra nelle caratteristiche che si desidera implementare, allora bisogna pensare ad un bel po' di cose oltre a quelle già citate.
Ovviamente non si vuol fare uno scrippettino scolastico...sarebbe troppo semplice
-
@LowLevel said:
Intendi usare Javascript per codificare la password?
Se vuoi, spiego. Ma ti anticipo che sarò costretto a scrivere un bel po' di roba, per spiegare come funziona (il codice finale sarà invece pochissimo), quindi decidi tu se è il caso di introdurre queste caratteristiche al progetto o se queste spiegazioni lo complicherebbero troppo.
-
@linus said:
@LowLevel said:
E se io scopro in qualche modo l'ID di sessione di un utente e provo a collegarmi al server spedendo quell'ID, come fa il sistema ad evitare di scambiarmi per quell'utente?
E' un pò difficile fare una cosa del genere
A seconda dei casi, può rivelarsi facilissimo.
Ad esempio, molte installazioni si PHP sono configurate in modo da accodare automaticamente ad ogni URL un parametro con l'ID di sessione nel caso in cui l'utente non abbia i cookie attivi.
Nel momento in cui gli ID di sessione appaiono negli URL, basta seguire un qualsiasi link verso un altro sito con il referer attivo nel browser per far memorizzare nei log del sito di destinazione l'ID usato dall'utente sul sito da cui proviene.
Concordo pienamente anche perchè se fai un semplice schema E-R ti accorgi subito che non ha senso avere 2 tabelle.
Io mi riferivo al fatto che si può usare una singola SELECT anche in presenza di due tabelle.
Se non sbaglio in MySQL c'è un bel comandino MD5(password) per inserire la pw criptata nel db...
La soluzione passa infatti da algoritmi per il calcolo di checksum, come md5(), ma c'è modo di aumentare ulteriormente la sicurezza facendo qualcosa in più oltre alla semplice memorizzazione dell'md5() della password.
Ossia, arrivo, mi loggo, inserisco sessione e ip nel db e poi ad ogni pagina controllo questa coppia...
Infatti si fa così. Ma per coprire anche i casi in cui più utenti siano dietro lo stesso firewall/proxy e presentino quindi lo stesso IP, può essere una buona idea aggiungere qualche controllo sull'user-agent. Ma solo in alcuni casi.
Ovviamente non si vuol fare uno scrippettino scolastico...sarebbe troppo semplice
Io sto attendendo un nulla-osta perché è la prima volta che leggo di questi vostri progetti e non ho idea di come funzionino. Cioè, non so se bisogna attenersi alla traccia fornita da PaTeR oppure se può essere ampliata. Per tale ragione, aspetto chiarimenti da PaTeR, che mi pare sia il promotore del progetto.
-
in un caso studio si cerca di trovare assieme la soluzione migliore rimanendo in bilico tra la funzionalità del progetto e gli esempi "a scopo didattico".
la relazione uno a uno tra due tabelle, personalmente, viene usata quando mi trovo a dover interrogare una tabella da più di 20 campi (numero indicativo) dove i campi che effettivamente mi interessano sono pochissimi (2 o 3) ed il numero di record è potenzialmente elevato.
Per dare un esempio concreto su cui ragionare senza inventarsi un progetto ad hoc per spiegare il concetto, l'anagrafica utenti calza a pennello.
Se l'anagrafica utenti avesse tutti i campi necessari per memorizzare vita morte e miracoli degli utenti (indirizzi, vari numeri di telefono, vari siti email e chi più ne ha più ne metta) e si raggiunge una dimensione di 30-40 campi per fare semplicemente il login non voglio far girare un tabellone così grande ed in questo caso separo le due tabelle in una striminzita che quindi sarà snella e veloce e l'altra (più grossa e lenta) che verrà interrogata solo quando saranno effettivamente necessarie tutte le info.
pro e contro:
pro:
una maggiore velocità di esecuzione quando faccio il login perchè devo interrogare una tabellina di pochi campi e ben indicizzata (gli indici li vedremo quando analiziamo come fare le tabelle nel dettaglio).contro:
una lentezza leggermente maggiore quando il motore deve estrarre i dati completi del singolo utente in quanto dovrà risolvere un join.l'interrogazione nel primo caso sarà:
select * from utenti where (condizioni)nel secondo sarà:
select (dati che mi interessano) from utenti, utenti_info_aggiuntive where utenti.id = utenti_info_aggiuntive.id_utente where (condizioni)pareri?
-
@Tymba said:
pareri?
Sì. Che oltre al motivo indicato da te, la soluzione multi-tabella è generalmente indicata per progetti destinati a possibili ampliamenti.
Se un sito possiede forum, blog e sondaggi e tutti e tre questi servizi beneficiano dell'autenticazione degli utenti, ha senso creare una tabella con le informazioni generiche e valevoli per tutti i servizi (username, password, IP, ecc.) ed una tabella in più per ciascuno dei servizi esistenti, contenente solo le informazioni-utente relative al servizio al quale la tabella è dedicata.
Se un domani sarà necessario aggiungere un guestbook o un modulo per spedirsi messaggi privati, ci si limita a creare una nuova tabella per il nuovo servizio, senza toccare nessuna di quelle già esistenti.
Separare le informazioni relative all'autenticazione da quelle aggiuntive e non essenziali all'autenticazione è sempre una buona idea. Anche perché la tabella con le informazioni per l'autenticazione subisce query continue, anche una ad ogni caricamento di pagina, a seconda dell'implementazione. Meglio che sia piccola, come dicevi tu.
-
@ LowLevel: E' vero che io ho scritto il post, ma il progetto era già stato studiato tra i mods, quindi non seguire solo me, ma anche tutti gli altri mods.
Io ho solo dato una mano su come realizzare il DB, voi potete seguire quella traccia oppure potete modificarla a vostro piacimento.
Preferirei che questo progetto avesse anche finalità didattiche, come se fosse una vera pillola, in quanto sarebbe più facile da comprendere e da modificare o estendere. Quindi non sarebbe male se scriveste un pò di righe in più nel vostro post anche per spiegare cosa state facendo e come lo state facendo.
Per il fatto della password mandata in chiaro, sarebbe una buona cosa se ci spiegassi come fare per mandarla già criptata, perchè ripeto: tutto ciò che può riguardare un sistema di gestioni utenti è meglio inserirlo. E la sicurezza mi sembra rientrare in questi
Non fatevi venire strane idee su come un moderatore vedrà il vostro messaggio: al massimo vi aiuterà a migliorarlo, di certo non vi
-
http://pajhome.org.uk/crypt/md5/
E' usato per convertire in MD5 tramite Javascript
-
Ok, PaTeR, adesso mi è chiaro. Grazie dei chiarimenti.
Espongo quello che farei io per migliorare la sicurezza del sistema di autenticazione. Visto che sono ancora allo stadio progettuale, a mio parere è presto per scrivere codice. Penso che sia il caso di farlo solo dopo aver raggiunto un accordo comune sul sistema da implementare, che può variare a seconda del contributo di tutti gli interessati.
Problema: la password non dovrebbe essere trasmessa in modo tale che un eventuale intercettatore la possa utilizzare per loggarsi.
Considerazioni: è evidente che limitarsi a criptare la password con un algoritmo come md5() e progettare il sistema in modo che il server accetti dal login dell'utente la password criptata con md5() non serve a nulla, perché se il sistema si accontenta della password criptata con md5() allora è sufficiente che l'intercettatore intercetti la password criptata e la invii al server. In poche parole il livello di sicurezza non è stato aumentato di una virgola rispetto all'uso della password in chiaro. [parlare di criptazione con md5() è improprio, ma sorvoliamo per semplicità]
Soluzione: la password inserita dall'utente non va trasmessa in nessun modo. Al contrario, è meglio trasmettere un'informazione (che chiameremo "informazione combinata") che si basa sia sulla password inserita dall'utente sia su un valore/stringa casuale, generato dal server ad ogni login e che solo il server conosce. Il calcolo di questo valore combinato spetta a Javascript e viene effettuato prima di spedire i contenuti del form di login.
Quando l'informazione combinata viene ricevuta dal server, il server controlla se essa è identica a quella che viene fuori combinando la stringa casuale precedentemente generata, che il server deve conoscere, con la password dell'utente, che in teoria dovrebbe essere presente nel database. In altre parole il server fa lo stesso calcolo fatto precedentemente dal Javascript, ma usando la password archiviata invece di quella inserita dall'utente (e che il form non spedisce): se il valore ricevuto e quello calcolato coincidono, allora l'utente ha inserito la giusta password.
Nasce però il problema che, per effettuare il calcolo, il server deve essere a conoscenza della password dell'utente. Ma memorizzare la password in chiaro nell'archivio non è una buona regola. Pertanto si introduce un livello di criptazione in più in modo che l'informazione combinata venga calcolata (sia dal Javascript che dal server) non combinando il valore casuale con la password in chiaro bensì combinando il valore casuale con un md5() della password. Il server quindi si può accontentare di memorizzare in archivio non la password in chiaro ma il suo md5(), ed il problema è risolto.
Sicurezza: se l'intercettatore intercetta l'informazione combinata, non se ne fa nulla. Quando l'intercettatore prova a fare il login, il server creerà infatti un valore casuale diverso rispetto a quello generato in precedenza per l'utente. Il server si aspetta di ricevere un'informazione combinata che si basa sul nuovo valore casuale, ma l'intercettatore ha in mano solo un'informazione combinata generata in base ad un precedente valore causale. Quindi gli è impossibile effettuare il login con quello che ha intercettato.
Implementazione:
-
Al login, il server genera un valore casuale, lo memorizza in una variabile di sessione e lo scrive fisicamente nel codice Javascript contenuto nella pagina, assegnandolo ad una variabile Javascript.
-
Quando l'utente invia il form con i dati, viene chiamata una funzione Javascript che calcola innanzitutto l'md5() della password, e poi l'informazione combinata, ovvero l'md5() del "valore casuale più l'md5() della password".
-
I contenuti del campo della password nel form vengono cancellati e la funzione Javascript assegna l'informazione combinata ad un campo hidden del form.
-
I contenuti del form vengono finalmente inviati al server attraverso il metodo post.
-
L'eventuale intercettatore intercetta il valore combinato, ma non se ne farà nulla.
-
Il server riceve il valore combinato e controlla che sia effettivamente ciò che esce fuori facendo l'md5() del valore casuale (che sta in una variabile di sessione) con l'md5() della password (che sta nel database).
-
Se i valori corrispondono allora l'utente ha inserito la giusta password e il sistema di autenticazione considera l'utente autenticato.
Note informatiche: che cosa diavolo è questo md5()? md5() è un algoritmo che, partendo da una stringa di byte di qualunque lunghezza, genera una stringa di sedici byte che può essere considerata l'impronta digitale (in gergo chiamata hash o fingerprint) della stringa di partenza.
L'md5() non è un algoritmo di criptazione che permette di risalire dall'impronta alla stringa originale, perché ad ogni impronta corrispondono infinite stringhe di partenza. In altre parole, non c'è una corrispondenza uno-ad-uno tra stringa di partenza ed impronta bensì una corrispondenza molti-ad-uno, ovvero stringhe di partenza diverse possono generare impronte identiche.
Nonostante questa limitazione, dovuta al semplice fatto che le combinazioni in sedici byte sono tante ma pur sempre finite, l'algoritmo è stato progettato in modo tale che variazioni minime nella stringa di partenza generino variazioni gigantesche nelle impronte corrispondenti. Quindi non c'è pericolo che l'md5() della password "pippo" sia simile a quello della password "peppo": le impronte delle due stringhe saranno completamente diverse.
Questo implica che, pur progettando un sistema di autenticazione che archivia non le password ma le impronte md5() delle password, è estremamente improbabile che qualcuno becchi una password che generi lo stesso valore md5() della vera password dell'utente.
-
-
Davvero Ottimo
Ora non resta che l'implementazione in JS...
-
Codice HTML del form di login:
<form name="login" method="post" action="<? echo $_SERVER['PHP_SELF']; ?>" onsubmit="encrypt();"> Nome utente: <input type="text" name="username"> Parola di accesso: <input type="password" name="pw"> <input type="hidden" name="md5ed" value=""> <input type="hidden" name="login" value="1"> <input type="submit" value="Accedi"> </form>
Codice Javascript:
<script type="text/javascript" src="md5.js"></script> <script type="text/javascript"> <!-- function encrypt () { <? echo "var challengeword = '" . $_SESSION['challengeword'] . "' ;" ; ?> var pw = document.login.pw.value ; if (pw) { pw = md5 (pw) ; pw = md5 (pw + challengeword) ; document.login.pw.value = '' ; document.login.md5ed.value = pw ; } } // --> </script>
La variabile di sessione challengeword è il valore casuale con cui la password inserita dall'utente viene combinato.
Può essere generata scrivendo in cima alla pagina un po' di codice PHP, del tipo:
$_SESSION['challengeword'] = md5 (mt_rand ());
Ovviamente la sessione deve essere già attiva.
Chi scrive il codice PHP per il controllo del login? Sempre io?
-
Vediamo qualche altro partecipante...
-
i miei complimenti
veramente uno spunto OTTIMO su cui ragionare.
ho letto con molta attenzione quanto scritto ed ora devo metabolizzare
-
@Tymba said:
i miei complimenti
veramente uno spunto OTTIMO su cui ragionare.
ho letto con molta attenzione quanto scritto ed ora devo metabolizzare :)non sei l'unico, appena imparato da lowlevel ho aggiornato il mio sistema di log
-
l' idea di LowLevel è di una praticità ed efficacia disarmanti, non è che mi trovi spesso a gestire l'autenticazione degli utenti, comunque non avevo mai pensato ad usare un metodo simile, quindi intanto subito un bel grazie .
Adesso mi guardo bene bene il codice e preparo una mia versione del controllo login in PHP.
-
@emmebar said:
l' idea di LowLevel è di una praticità ed efficacia disarmanti, non è che mi trovi spesso a gestire l'autenticazione degli utenti, comunque non avevo mai pensato ad usare un metodo simile, quindi intanto subito un bel grazie .
Adesso mi guardo bene bene il codice e preparo una mia versione del controllo login in PHP.Poi magari cerca di integralrla qui, così vediamo di curare un'altro aspetto del progetto
-
Fino a ieri il mio bizzarro sistema di autenticazione faceva in modo che le password fossero memorizzate nell' id_sessione in chiaro. Ho risolto (adesso non lo sono più).
Adesso però devo trovare il modo per non trasmettere più la password utente nel form di login ma bensì quell'informazione combinata di cui si è parlato.
L'informazione combinata deve tenere conto di due fattori:
stringa casuale che solo il server conosce;
password inserita nel formPosso creare una funzione personalizzata (stringa/password) per generare l'informazione combinata? Se ho capito bene la risposta è SI.
Deve essere obbligatoriamente in javascript la funzione? La risposta è NO se ho capito.
-
@linus said:
Fino a ieri il mio bizzarro sistema di autenticazione faceva in modo che le password fossero memorizzate nell' id_sessione in chiaro. Ho risolto (adesso non lo sono più).
Adesso però devo trovare il modo per non trasmettere più la password utente nel form di login ma bensì quell'informazione combinata di cui si è parlato.
L'informazione combinata deve tenere conto di due fattori:
stringa casuale che solo il server conosce;
password inserita nel formPosso creare una funzione personalizzata (stringa/password) per generare l'informazione combinata? Se ho capito bene la risposta è SI.
Deve essere obbligatoriamente in javascript la funzione? La risposta è NO se ho capito.Si, il java script si