Quali sono le migliori pratiche da utilizzare in uno script di accesso PHP?


27

Voglio riscrivere i miei script di accesso per i siti Web dei clienti per renderli più sicuri. Voglio sapere quali migliori pratiche posso implementare in questo. I pannelli di controllo protetti da password sono in abbondanza, ma pochissimi sembrano implementare le migliori pratiche in termini di scrittura del codice, velocità e sicurezza.

Userò PHP e un database MYSQL.

Usavo md5, ma vedo che sha256 o sha512 sarebbero migliori (insieme a hash e salt sicuri).

Alcuni script di accesso registrano l'indirizzo IP durante la sessione o anche l'agente utente, ma voglio evitarlo poiché non è compatibile con i server proxy.

Sono anche un po 'indietro rispetto alle migliori pratiche nell'uso delle sessioni in PHP 5 (l'ultima volta che ho letto è stato PHP 4), quindi alcune migliori pratiche con questo sarebbero utili.

Grazie.


1
Lancia la tua sceneggiatura su codereview.SE!
Chris,

@Chris CodeReview aiuta con chiarezza del codice e simili. Non dovresti assolutamente andare da loro per motivi di sicurezza. Semmai, ti ricorderanno quasi sempre di non "tirare il tuo", che è sostanzialmente la stessa risposta che otterrà in qualsiasi comunità di programmazione su SE.
Alternatex,

Risposte:


21

La cosa migliore è non reinventare la ruota. Ma, capisco, nel mondo PHP potrebbe essere difficile trovare un componente di alta qualità che già lo fa (anche se sono abbastanza sicuro che i framework implementano tali cose e le loro implementazioni sono già testate, solide, revisionate da codice, ecc. )

Se, per alcuni motivi, non è possibile utilizzare un framework, ecco alcuni suggerimenti:

Suggerimenti relativi alla sicurezza

  • Usa PBKDF2 o Bcrypt se puoi . È fatto per quello.

    Razionale: entrambi gli algoritmi possono rallentare arbitrariamente il processo di hash, che è esattamente quello che vuoi quando le password di hashing (alternative più rapide significano forza bruta più semplice). Idealmente, è necessario regolare i parametri in modo che il processo diventi sempre più lento nel tempo sullo stesso hardware, mentre viene rilasciato un nuovo hardware più veloce.

  • Se non puoi, almeno non usare MD5 / SHA1. Mai. Dimenticalo . Utilizzare invece SHA512, ad esempio. Usa anche il sale.

    Motivazione: MD5 e SHA1 sono troppo veloci. Se l'attaccante ha accesso al tuo database contenente gli hash e ha una macchina (nemmeno particolarmente) potente, forzare brutalmente una password è semplice e veloce. Se non ci sono sali, aumentano le possibilità che l'attaccante trovi la password effettiva (il che potrebbe causare danni aggiuntivi se la password fosse riutilizzata altrove).

  • In PHP 5.5.0 e versioni successive, usa password_hashe password_verify.

    Motivazione: chiamare una funzione fornita dal framework è semplice, quindi il rischio di commettere un errore è ridotto. Con queste due funzioni, non devi pensare a parametri diversi come l'hash. La prima funzione restituisce una singola stringa che può quindi essere memorizzata nel database. La seconda funzione utilizza questa stringa per la verifica della password.

  • Proteggiti dalla forza bruta . Se l'utente invia una password errata quando ha già inviato un'altra password errata 0,01 secondi fa, è una buona ragione per bloccarla. Mentre gli esseri umani possono scrivere velocemente, probabilmente non possono essere così veloci.

    Un'altra protezione sarebbe quella di impostare un limite di guasti all'ora. Se l'utente ha inviato 3600 password errate in un'ora, 1 password al secondo, è difficile credere che si tratti di un utente legittimo.

    Razionale: se le tue password sono incise in modo non sicuro, la forza bruta può essere molto efficace. Se le password vengono archiviate in modo sicuro, la forza bruta sta ancora sprecando le risorse del server e la larghezza di banda della rete, causando prestazioni inferiori per gli utenti legittimi. Il rilevamento della forza bruta non è facile da sviluppare e da ottenere, ma per qualsiasi altro sistema, ne vale la pena.

  • Non chiedere ai tuoi utenti di cambiare le loro password ogni quattro settimane. Questo è estremamente fastidioso e riduce la sicurezza, poiché incoraggia la sicurezza post-it.

    Razionale: l'idea che forzare la modifica delle password ogni n settimane protegge il sistema dalla forza bruta è sbagliata. Gli attacchi di forza bruta di solito hanno successo in pochi secondi, minuti, ore o giorni, il che rende irrilevanti le modifiche mensili della password. D'altro canto, gli utenti non sono in grado di ricordare le password. Se, inoltre, devono modificarli, tenteranno di utilizzare password molto semplici o semplicemente annoteranno le loro password sui post-it.

  • Controlla tutto, ogni volta. Archiviare gli accessi, ma non archiviare mai le password nel registro di controllo. Assicurarsi che il registro di controllo non possa essere modificato (ad esempio, è possibile aggiungere dati alla fine, ma non modificare i dati esistenti). Assicurarsi che i log di controllo siano soggetti a backup regolari. Idealmente, i log dovrebbero essere archiviati su un server dedicato con accessi molto restrittivi: se un altro server viene violato, l'attaccante non sarà in grado di cancellare i log per nascondere la sua presenza (e il percorso intrapreso durante l'attacco).

  • Non ricordare le credenziali dell'utente nei cookie, a meno che l'utente non lo richieda (la casella di controllo "Ricordami" deve essere deselezionata per impostazione predefinita per evitare errori umani).

Suggerimenti di facilità d'uso

  • Consentire all'utente di ricordare la password, se lo desidera, anche se la maggior parte dei browser dispone già di questa funzione.
  • Non utilizzare l'approccio di Google quando invece di chiedere nome utente e password, a volte all'utente viene richiesta solo la password , il nome utente è già visualizzato in a <span/>. I browser non possono riempire il campo della password in questo caso (almeno Firefox non può farlo), quindi costringe a disconnettersi, quindi ad accedere con un modulo normale, compilato dal browser.
  • Non utilizzare i popup abilitati per JavaScript per l'accesso. Rompe le funzionalità di ricordare la password del browser (e fa schifo in tutti i casi).
  • Consenti all'utente di inserire il suo nome utente o il suo indirizzo e-mail . Quando mi registro, a volte il nome utente che voglio inserire è già preso, quindi devo inventarne uno nuovo. Ho tutte le possibilità di dimenticare questo nome tra due ore.
  • Tieni sempre un link alla funzione "Password dimenticata" vicino al modulo di accesso. Non visualizzarlo solo quando l'utente non ha effettuato l'accesso: l'utente che non ricorda affatto la sua password non ha idea di dover inviare una password errata per visualizzare il link "Password dimenticata".
  • Non usare la sicurezza per post-it .
  • Non inventare stupide regole relative alla password per renderla più debole . Esempio: "La tua password deve iniziare con una lettera minuscola."; "La tua password non può contenere spazi."

Non imbatterti in bcrypt. Qual è il tuo ragionamento per raccomandarlo? Perché non md5 / sha1? Grazie per il resto dei suggerimenti!
baritoneuk,

Il ragionamento è semplice: bcryptè fatto da persone altamente qualificate. È anche testato, esaminato, ecc. Quindi non c'è motivo di implementare la stessa cosa da soli. È come creare il tuo algoritmo di crittografia per il tuo sito web. * "Why not md5 / sha1?": Vedi ad esempio en.wikipedia.org/wiki/MD5#Security
Arseni Mourzenko

5
bcrypt è lento e come detto implementato dai professionisti. md5 è un algoritmo di hashing non una crittografia che non è esattamente la stessa cosa. Hashing di un file veloce è buono, md5 sarebbe usato qui ... hashing una password non deve essere così veloce, bcrypt può aiutare qui. Il motivo per cui dico questo è che la forza bruta diventa più difficile quando l'algoritmo di cripta è "lento".
Chris,

2
@baritoneuk: il minimo è bello. Ma non riesco a contare il numero di siti a cui ho avuto restrizioni come lunghezze massime , nessun carattere non alfanumerico, ecc. Sconcertante, se hai intenzione di hash la password comunque - il che mi fa preoccupare che non lo siano , lo stanno semplicemente archiviando nel loro database in chiaro.
Carson63000,

1
@Brian Ortiz: non sempre. A volte è una buona idea fissare un limite. Se non lo fai, verifichi se la tua applicazione funziona per una durata? Come? Se non lo collaudi, come puoi essere sicuro che funzioni? Invece, quando si imposta un limite su un valore ragionevole, come 100, è possibile verificare facilmente una password di 100 caratteri.
Arseni Mourzenko,

6
  1. Il tuo sito dovrebbe usare HTTPS. In nessun caso è necessario presentare una pagina di accesso o accettare accessi da una connessione non crittografata.
  2. I cookie devono essere limitati solo a HTTP e alle connessioni sicure se si utilizza HTTPS.
  3. Il processo di accesso non dovrebbe richiedere meno di 2 secondi (1 se si ritiene che 2 secondi siano troppo lunghi). Utilizzare un hash sicuro quando si archiviano e si verificano le password e si usa un sale più difficile da indovinare. Utilizzare bcryptse possibile. Altrimenti, usa qualche altro tipo di hash iterato.
  4. Mai e poi mai comporre le query del database in alcun modo che richieda l'utilizzo di funzioni come mysql_real_escape_string. Non utilizzare mai la concatenazione di stringhe per creare la query. Usa query preparate e parametrizzate. La maggior parte, se non tutti, i driver DB per PHP lo supportano. Se non sai come farlo, passare un po 'di tempo di apprendimento come prepare, binde executeutilizzando qualsiasi DB che si sta utilizzando. È l' unico modo sicuro per proteggerti dall'iniezione SQL. DOP lo supporta.
  5. Incoraggia i tuoi utenti a non usare la stessa password che usano per la loro e-mail. Ricorda loro che se il tuo sito è compromesso e se usano la stessa password in entrambi i posti, qualcuno può dirottare la loro email.

+1 per HTTPS, poiché c'è sempre più traffico attraverso le reti WiFi pubbliche. Ma non sono d'accordo con il punto 3: 2 secondi è troppo lungo dal punto di vista degli utenti. 0,5 s. va bene, specialmente se si usano altre tecniche anti-bruta.
Arseni Mourzenko,

Sono confuso sul punto numero 4. Come sfuggire alla convenzione di escape dei dati con mysql_real_escape_string? Tutti i dati inviati dagli utenti non devono essere attendibili e filtrati di conseguenza.
chrisw,

@chrisw: Sì, tutti gli input dell'utente devono essere gestiti come se fossero dannosi. Ma quando si utilizzano query parametrizzate, è, tranne nessuno, il modo migliore per arrestare l'iniezione SQL . Se non si utilizzano query preparate e parametrizzate, si è vulnerabili all'iniezione SQL. mysql_real_escape_stringè falsa sicurezza, non è una garanzia. Le query con parametri sono.
Greyfade,

Sono d'accordo ora dopo aver fatto qualche ulteriore lettura al riguardo. La funzione: mysql_real_escape_string è generalmente sicura per la maggior parte, non la considero ENORME una responsabilità, ma posso vedere come l'utilizzo delle dichiarazioni preparate sia molto più efficiente.
chrisw,

1
Puoi usare DOP.
Felix G,

1

Usa un hash unidirezionale salato (preferibilmente SHA512 usando http://au2.php.net/manual/en/function.hash.php ) ... in questo modo, se qualcuno hackera il tuo database, anche se conosce il sale , non possono estrarre le password (senza una tabella arcobaleno, che sarebbe troppo lunga per SHA512).

Usa HTTPS.

Non inviare conferme nome utente / password via e-mail all'utente al momento della registrazione.

Se si accettano i cookie per "ricordami", aggiungere un ulteriore accesso per accedere alle funzioni di amministrazione e modifica del profilo.

Se un utente sbaglia una password, non dire che ha sbagliato la password (dire che ha sempre sbagliato "nome utente o password") - in questo modo, meno indizi su quali sono i nomi utente validi.

Prova a implementare il nome dello schermo rispetto al login: in questo modo, meno utenti visualizzeranno il loro nome di accesso nelle schede degli utenti.


Completamente d'accordo con il bit sul non inviare e-mail in testo normale tramite e-mail. Ho perso il conto delle volte che i siti web lo fanno. Se hai 1 password per tutti i siti (che per fortuna non ho), potenzialmente tutti i siti Web sono compromessi. Tali siti web probabilmente memorizzano anche le password in testo semplice. sigh
baritoneuk,

1
  • Non usare mai algoritmi di hashing MD5 o SHA1. Attenersi sempre a quelli più recenti come SHA512
  • Utilizzare sempre un sale fortemente generato casualmente
  • Non inviare mai le password agli utenti, anche in caso di "Password dimenticata"
  • Non usare mai le funzioni mysql_ *. Sono da tempo ammortizzati. Attenersi alla DOP
  • Non archiviare mai le password in sessioni o cookie

0

Ecco un piccolo consiglio: assicurati che non sia possibile accedere ai tuoi cookie con JS per prevenire il furto, vedi Protezione dei cookie: HttpSolo articolo di Jeff Atwood

... Attraverso una costruzione intelligente, l'URL malformato riesce solo a passare oltre il disinfettante. Il codice di rendering finale, quando visualizzato nel browser, carica ed esegue uno script da quel server remoto.

... chiunque carichi questa pagina del profilo utente iniettato di script ha trasmesso involontariamente i cookie del proprio browser a un server remoto malvagio!

Come abbiamo già stabilito, una volta che qualcuno ha i cookie del tuo browser per un determinato sito Web, essenzialmente hanno le chiavi del regno per la tua identità lì ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.