Impostazioni
Un sistema LAMP (Linux, Apache, MySQL, PHP). L'accesso a db avviene tramite l'interfaccia di loopback (forse non in futuro, dipende dalla soluzione di hosting).
Il db contiene una tabella con il nome utente, l'hash della password, la password con hash (e alcuni altri dati irrilevanti per questa discussione). L'utente DB per l'app ha solo il permesso di esecuzione, limitando l'accesso solo alle stored procedure.
Soluzione comune
Applicazioni PHP:
- Leggi salt e hashedPW utilizzando "
select * from table where user=?
" - Hash ha immesso la password con salt e fa un confronto di stringhe in app a hashedPW da DB (so che password_hash e password_verify ora sono migliori, ma è ancora meglio?)
- Se le stringhe corrispondono, l'utente è autenticato.
La mia soluzione
Il database ha alcune stored procedure (SP) rilevanti per questa discussione:
-
check_user(user, HTTP_USER_AGENT, REMOTE_ADDR)
SP restituisce unview
della tabella utenti che restituisce il sale solo se il nome utente viene trovato nella query. -
check_password(user, hashedPW, HTTP_USER_AGENT, REMOTE_ADDR)
SP restituisce un codice di sessione univoco (che viene creato eseguendo un hashing debolmente una stringa casuale con i parametri del parametro HTTP_USER_AGENT + REMOTE_ADDR) se l'hash corrisponde o nulla se non lo è. questo codice di sessione viene quindi memorizzato in una variabile SESSION da utilizzare in ciascuna chiamata di stored procedure al DB per autenticare l'accesso.
Applicazioni PHP:
- controlla l'utente esistente nel sistema "
call check_user(user, HTTP_USER_AGENT, REMOTE_ADDR)
". - Se viene trovato
user
e l'indirizzo non è bloccato, DB registra la ricerca del nome utente, restituisce salt. - Se REMOTE_ADDR è bloccato, registra e restituisce 0
- Hash ha immesso la password con sale e invia la stringa al DB utilizzando "
call check_password(user, hashedPW, HTTP_USER_AGENT, REMOTE_ADDR)
". - DB controlla la lista degli IP banditi, se username, remote_addr & Corrispondenza HTTP_USER_AGENT, DB registra l'autenticazione non riuscita, DB restituisce 0
- Se le stringhe corrispondono, il DB registra un'autenticazione corretta, DB restituisce i dati degli utenti nell'elenco.
- Se le stringhe non corrispondono, DB registra l'autenticazione non riuscita, DB restituisce 0.
Ragionamento
La mia soluzione consente:
- L'hash viene eseguito in PHP, che consente di eseguire più elaborazioni (cicli / cicli?) sull'hashing, algoritmi di hashing migliori (come Argon2).
- L'utente SQL può essere configurato con autorizzazioni limitate solo per eseguire stored procedure, in questo modo, anche se il nome utente e la password di connessione SQL vengono violati, può essere utilizzato solo per ottenere i dati forniti nelle stored procedure già nel DB e nient'altro, quindi non può ottenere un elenco completo di utenti e non può ottenere un elenco completo di hashedPW.
- Gli attacchi di forza bruta possono essere rilevati a livello di test del nome utente e fermati lì, richiedendo solo una chiamata DB per bloccare gli attacchi di forza bruta.
- Il client viene visualizzato come nome utente o password non validi, indipendentemente dal fatto che
check_user
ocheck_password
non riescano.
Ci sono degli svantaggi in questa soluzione?
l'unico che riesco a vedere al momento è che non può usare [password_hash] che sembra essere il metodo preferito.
Ho esaminato le altre risposte a una domanda simile (qui: È una buona idea lasciare che un database faccia un controllo della password? e altrove), e la maggior parte delle persone afferma che l'hashing è fatto meglio nel codice PHP, per consentire il multi-threading (gestito da apache) e non legare il motore SQL con le cose per cui non è veramente progettato, quindi ho trovato il precedente ... tutti i feedback ricevuti con gratitudine.
PS ho appreso per la prima volta PHP circa 20 anni fa, ma non ho mai toccato questo o altri web dev in quasi 10 anni, quindi sii gentile.