Perché archiviare le password degli utenti?


10

A volte vedo domande che chiedono come archiviare in modo sicuro le password degli utenti per un'applicazione Web (utilizzando un RDBMS, non sto parlando di Facebook o Twitter). La solita risposta è "salt la password, quindi l'hash con un algoritmo forte come TDES o SHA512".

La mia domanda è: come utente RDBMS, perché dovrei preoccuparmi della memorizzazione della password problematica dal momento che la maggior parte dei motori ha un meccanismo di autenticazione incorporato.

Ad esempio, se un utente X desidera creare una password utente account Y sulla mia applicazione Web, come sta sbagliando la seguente query:

CREATE USER X WITH ENCRYPTED PASSWORD Y IN GROUP baseuser;

Quindi, all'interno della mia applicazione, l'utente può aprire una connessione al database usando le sue credenziali e non devo preoccuparmi affatto della gestione delle password.

Vedo molti vantaggi di questo metodo:

  • Se RDBMS decide che l'algoritmo di crittografia deve essere modificato, non ho bisogno di toccare nulla, solo per applicare gli aggiornamenti di sicurezza;
  • È facile per me gestire le autorizzazioni degli utenti. Se un utente viene promosso al ruolo di amministratore, devo solo aggiungere l'utente al gruppo corrispondente;
  • Le iniezioni di SQL sono ora prive di significato, poiché gestisco le autorizzazioni per consentire esattamente ciò che desidero consentire a ciascun utente nel database (ad esempio, in un forum come SO, aggiungendo nuovi post, rispondendo ai post, commentando e modificando / eliminando le proprie domande / risposte / commenti);
  • Un account utente "anonimo" può essere utilizzato per connessioni non autenticate alla mia applicazione;
  • Ogni utente è il proprietario dei dati forniti.

Ma praticamente su ogni domanda che vedo su questo argomento, sembra esserci un consenso generale sul fatto che non è così che devono essere fatte le cose. La mia domanda è: perché?

Nota: il terzo punto è consentito dai criteri in PostgreSQL e dai criteri di sicurezza in Microsoft SQL Server. Mi rendo conto che questi concetti sono nuovi arrivati, ma comunque, ora che sono qui, perché la tecnica che descrivo non diventa il modo standard di gestire gli account degli utenti?


2
I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
Paul White 9

Per inciso, la solita risposta è sbagliata. Dovresti salare la password, quindi l'hash con un algoritmo lento come bcrypt o argon2.
Tgr

Risposte:


27

Perché per molte applicazioni, non vogliono che i singoli account utente si connettano al database. Gli utenti / password / diritti / autorizzazioni sono tutti gestiti a livello di applicazione e un singolo account di servizio dedicato viene utilizzato per connettersi al back-end del database.

Come DBA, non voglio gestire, a livello di database, i 10.000 utenti attivi di alcune applicazioni web di medie dimensioni rivolte al pubblico, o forse i 2+ milioni di utenti di alcune app improvvisamente popolari.

In un senso molto reale, questa è una differenza nella filosofia tra sviluppatori di applicazioni e sviluppatori di database / DBA.

Molti / la maggior parte degli sviluppatori di applicazioni non vorranno trasferire la responsabilità per i principali aspetti della funzionalità dell'app e / o delle regole aziendali al livello del database. Al contrario, visualizzano il database come uno strumento per archiviare e recuperare semplicemente i dati.

In alcuni casi, questo potrebbe essere miope; molti RDBMS hanno fantastiche funzionalità che potrebbero rendere la vita degli sviluppatori di app molto più semplice (sicurezza a livello di riga, indici colonnari, archiviazione di filestream, ecc.).

Ma alcune di queste funzioni più interessanti sono disponibili solo nelle versioni più recenti e le organizzazioni non sono sempre veloci per aggiornare gli ambienti esistenti (vedere questo grafico dal 2014 ).

E in altri casi, è preferibile gestire quelle cose a livello di applicazione (e non solo per la portabilità della piattaforma di database, francamente penso che l'affermazione sia esagerata).


2
Esiste una "guerra santa" esistente nel fatto che la logica aziendale vada nell'applicazione o nel database. Se hai creato un'applicazione in cui tutta la logica aziendale (in particolare la sicurezza) si trova nel database (usando stored procedure, viste ecc.), Potrebbe esserci un argomento per utilizzare i meccanismi di sicurezza del database perché nessuno può connettersi direttamente e aggirare il tuo sicurezza. Concordo pienamente sul fatto che dovresti evitare di "ricostruire" un meccanismo di sicurezza (ad esempio login / pasword) in una tabella personalizzata. Perché farlo quando si dispone già della protezione active directory / O365.
Nick.McDermaid,

1
@ Nick.McDermaid Mi piace assicurarmi di mescolare equamente la logica di business tra DB e applicazione per aiutare a eliminare il potenziale per i futuri sviluppatori di avere la minima idea di cosa stia succedendo, mi aiuta anche a mantenere la sicurezza del mio lavoro poiché nessuno è pazzo abbastanza da volerlo gestire.
Der Kommissar,

Lancia un servizio Web e un server applicazioni Tomcat e potresti lavorare per IBM
Nick.McDermaid,

8

La linea di demarcazione sta diventando un po 'soffice a quel punto, ma considererei gli utenti e le autorizzazioni a livello di database come parte dello schema e non parte dei dati, e in generale le applicazioni non hanno spazio per modificare lo schema (ci sono, come sempre, eccezioni a questa regola).

Preferirei non dare alle applicazioni le autorizzazioni necessarie per gestire gli oggetti dello schema (accessi, utenti e autorizzazioni) quando sono necessari nuovi utenti e quelli vecchi se ne vanno, perché se quell'applicazione viene hackerata l'attaccante ha accesso a tali autorizzazioni semplificando ulteriormente l'apertura del database. In MS SQL Server, a meno che non si utilizzino database completamente contenuti, gli accessi sono oggetti a livello di server, pertanto è necessario distribuire diritti oltre il singolo database dell'applicazione, rendendolo ancora più rischioso.

Inoltre, anche se si dispone di account utente per applicazione a livello di database, è comunque necessario disporre di account utente a livello di applicazione per gestire le richieste non autenticate, ovvero se l'applicazione necessita di informazioni dal database prima che l'utente dell'applicazione abbia eseguito l'autenticazione (forse per visualizzare le informazioni sullo stato nella schermata di benvenuto / login?).

Inoltre, se la portabilità tra i motori di database è un obiettivo (forse la tua app vuole essere in grado di funzionare sia su mysql sia su postgres?) Allora le tue applicazioni dovranno astrarre le funzioni di gestione utente / login per ciascun motore poiché non sono standard tra loro - se hai intenzione di fare questo sforzo, potresti anche implementare le password tu stesso e ottenere le opzioni di gestione che desideri invece di accettare il set di funzionalità comuni più basso offerto dai motori.


1
Ok, quindi "l'applicazione non dovrebbe alterare lo schema" è secondo me il primo buon punto contro la tecnica che suggerisco. Tuttavia, l'account anonimo in grado di creare nuovi utenti deve solo essere in grado di creare nuovi utenti con l'accesso di base. Solo gli amministratori possono promuovere gli utenti e rilasciarli, il che immagino sia ciò che si desidera nelle applicazioni :-) I dati generali sono visibili all'utente anonimo, quindi questa connessione può essere utilizzata per contenuti in cui non è necessaria l'autenticazione. Anche la portabilità è un buon punto, ma penso che i comandi utente siano ora parte dello standard (non sono sicuro, non lo era anni fa)
Fabian Pijcke,

A proposito con questa impostazione se un hacker ottiene l'accesso al database come utente anonimo, sarà in grado di creare tutti gli utenti che vuole, ma questo non è un problema di sicurezza, potrebbe anche gonfiare il database usando uno dei gli account creati, questo sarebbe fastidioso ma di nuovo nessun problema di sicurezza (e potrebbe farlo anche usando l'interfaccia standard comunque, sarebbe comunque molto più lento: p)
Fabian Pijcke,

3
Sono d'accordo che dal punto di vista della sicurezza gli utenti a livello di database sarebbero migliori. Tuttavia, ciò è praticamente impossibile da gestire, ad esempio con negozi online in cui potresti avere 50 milioni di utenti registrati. Ognuno dovrebbe essere un utente del database. Inoltre: questo in genere non funziona bene con le applicazioni Web che utilizzano un pool di connessioni.
a_horse_with_no_name

6

Riaffermando la domanda

Perché archiviare le password degli utenti?

La risposta più semplice è che devi farlo. Conserva ancora le password nel tuo metodo alternativo. È solo che si utilizza il sistema integrato del database per gestire l'archiviazione. Quindi il tuo metodo è valido solo come quello del tuo database. Potrebbe essere comunque meglio di qualsiasi cosa tu possa fare altrimenti, ma non sta evitando l'archiviazione. Evita davvero solo la memorizzazione dei codici.

Potrebbe anche non essere migliore. Se comprometto un database e ottengo copie dei file, posso accedere direttamente alle tabelle. Quindi non ha senso usare un brillante sistema di gestione delle password. Perché se qualcuno può accedere alla tabella a livello di sistema contenente le password o le password con hash, può anche accedere direttamente ai file. Perché preoccuparsi di crackare le password quando hai già i dati? Non è nemmeno possibile crittografare facilmente i dati. Ogni utente deve essere in grado di accedervi. Quindi la crittografia a livello di utente non funzionerà così bene.

Ma quello che sembra davvero chiederti è

Perché utilizzare uno schema di autenticazione a livello di applicazione quando il database ne ha già uno?

Sicurezza

Ignorando la possibilità di poter scrivere una versione più sicura, altri hanno suggerito una serie di motivi. Sono generalmente d'accordo. Ma ce n'è un altro che nessuno ha ancora menzionato. Stai compromettendo la sicurezza del tuo database.

In questo sistema, ogni utente dell'applicazione ha un utente e una password del database. Certo, è un utente limitato, ma è ancora un utente che può connettersi al database. Anche se si utilizza la sicurezza a livello di riga, si consente comunque agli utenti finali di conoscere le informazioni sulla connessione al database. Se c'è mai un exploit in cui un utente può ottenere l'accesso anche a livello di tabella, hai aperto il database per attaccare. E alcuni exploit sono andati oltre l'accesso all'amministratore.

Negli strati della cipolla di sicurezza, il sistema normale è:

  • Database, che consente solo connessioni da determinate macchine.
  • Database, consente le connessioni solo come determinate combinazioni utente / password.
  • Server con autorizzazioni per il database che consentono connessioni dalle applicazioni.
  • Le applicazioni vengono eseguite sul server.
  • Le applicazioni dispongono di informazioni sulla connessione al database con privilegi limitati.
  • Le applicazioni autenticano gli utenti prima di consentire loro di modificare il database (tranne possibilmente per creare nuovi account).

In questo sistema:

  • Gli utenti finali conoscono le combinazioni utente / password che funzioneranno sul database, certamente con privilegi molto bassi.
  • Devono solo comprendere un server o fingere in modo convincente di essere un server autorizzato.

Abbiamo perso l'intero livello di sicurezza dell'applicazione. E abbiamo volontariamente rinunciato a parte del livello del database. Quindi abbiamo bisogno solo di due exploit:

  1. Parodia o compromissione di un server autorizzato.
  2. Aumentare l'accesso dell'account con privilegi limitati.

Se possiamo fare queste due cose, abbiamo accesso al database. Quindi passiamo da tre strati fino a due. (Il terzo livello nel sistema normale è che è necessario un utente valido per connettersi al database.)

Farai molta gestione di questi account. E se commettessi un errore? Invece di limitare l'utente X solo a determinate righe, si dà a tutti l'accesso a una tabella critica. Questo tipo di cose viene normalmente eseguito manualmente e ce ne sono solo alcune, quindi sono facili da controllare. Ma nel tuo sistema, potresti fare migliaia o milioni o addirittura miliardi di account utente, ognuno con il proprio accesso idiosincratico.

Del resto, il sistema del database si ridimensiona a milioni o miliardi di utenti? In caso affermativo, che dire del numero di regole? Se ogni utente adotta un centinaio o più di regole su ciò che può e non può accedere, arriva a un miliardo di utenti? Stai prendendo un sistema normalmente su piccola scala e rendendolo su larga scala. Non funzionerà necessariamente. Man mano che cresci, potresti trovare dei limiti di sistema.


5

Quello che descrivi gestirà l'autenticazione, ma non l'autorizzazione (a quali dati l'utente può accedere) o solo nel caso più semplice del caso d'uso.

Per continuare con il tuo esempio con stackexechange: Come renderesti i messaggi eliminati visibili solo agli utenti con un alto livello di reputazione? Quindi, per le regole di accesso, avrai ancora bisogno di logica nel codice. Invece di condividere la logica di accesso tra le regole del database e le regole di accesso applicative, la maggior parte degli sviluppatori preferisce averle tutte nello stesso posto.

Avrai anche bisogno di una tabella per memorizzare le informazioni dell'utente: un utente non è solo un nome utente + password. Ha un'e-mail, una reputazione e così via. Quindi è ancora necessaria la tabella utente, che è necessario assicurarsi che sia sincronizzata con la tabella utente del database, a condizione che sia possibile accedervi.

Con la tua soluzione, puoi semplicemente omettere una colonna di password, che non è così difficile da compilare: ci sono buone librerie e documentazione su come gestire le password / hash.

Un altro punto: come creeresti un pool di connessioni? Conosco solo jdbc (java <-> db) e per ottenere una connessione è necessario fornire un nome utente + una password, che è quindi possibile raggruppare.

Ho pensato ad alcuni altri punti che saranno più difficili / più contorti da implementare rispetto al modo stabilito:

  • gestione del recupero password
  • 2 anni dopo l'implementazione iniziale, il responsabile del prodotto ti chiede di aggiungere il supporto per lo schema oauth o di autorizzare il doppio fattore

Qualcosa di simile CREATE POLICY deleted_posts_high_rep ON posts FOR SELECT TO baseuser USING ((SELECT rep FROM users WHERE name = current_user()) > 10000)risponde alla tua prima domanda. Non ho mai detto di non aver più bisogno di una tabella degli utenti e garantire la sincronizzazione con la tabella degli utenti del db è alquanto complicato ma possibile. Il punto principale della tecnica discussa è la sicurezza. Per quanto riguarda il pool di connessioni, lavoro con OCaml e devo dire che non capisco perché avrei bisogno di un pool di connessioni. Attualmente utilizzo una mappa hash che associa i valori dei cookie alle funzioni 0-ary che restituiscono connessioni :-)
Fabian Pijcke,

5
I pool di connessioni sono implementati per migliorare le prestazioni: con essi non è necessario stabilire una connessione per ogni richiesta dell'utente (quindi si risparmia cpu / io / latenza nella creazione del collegamento tcp + tutte le connessioni e lo scambio di autorizzazioni con il database). Per quanto riguarda la definizione della politica: il tuo database controllerà costantemente l'accesso su ogni accesso ai dati, anche quando li hai già controllati una volta. Anche "accesso negato o vietato" non equivale a "OK, nessun risultato". Non sono sicuro che i ragazzi della sicurezza preferirebbero la versione OK.
Thierry,

3
Fabian, il pool di connessioni è fondamentale in qualsiasi tipo di scala, è davvero un valore predefinito che non considereresti nemmeno di non utilizzare. Ecco alcuni parametri di riferimento solo per darti un'idea di quanto sia importante: aumento delle prestazioni 600x con il pool di connessioni ( vladmihalcea.com/2014/04/17/the-anatomy-of-connection- passaggi ) e aumento di oltre 4.000 volte con pool di connessioni ( progress.com/tutorials/jdbc/… ). Sono diversi ordini di differenza di grandezza, non è un "bello da avere", le app si fermerebbero senza di essa.
Ivan McA,

1
Numeri interessanti E in effetti, non ho mai visto un'applicazione che non utilizzava pool di connessioni. Ma non sapevo (e mi aspettavo) che facessero così tanto speedup. L'altro aspetto che si ottiene con il pool di connessioni è il controllo delle risorse: grazie a loro, un enorme aumento del client che tenta di connettersi contemporaneamente rallenterà l'applicazione, ma il database non ne risentirà tanto (se il pool è ben configurato) .
Thierry,

Ok, ho appena cercato ulteriori informazioni sui pool di connessioni e sono d'accordo che questo è un punto molto valido non appena il sito Web deve gestire più di cento connessioni al secondo, il che non è così elevato. Sembra che ogni connessione in PostgreSQL consumi circa 10 MiB di RAM! Non avrei mai pensato che fosse così tanto.
Fabian Pijcke,

1

Un altro punto: molte [1] applicazioni Web consentono di registrarsi e creare un account utente online tramite l'app stessa. Ciò significa che il tuo utente anonimo (che dovrebbe avere i privilegi minimi che uno si aspetterebbe) deve avere i diritti per creare utenti e concedere privilegi!

OK, potrebbe essere possibile limitare quali privilegi potrebbe concedere e dare agli utenti di livello superiore più opzioni di concessione (non sono consapevole che lo sia - non è "concedere privilegi" un singolo privilegio spesso). Tuttavia, significa mettere in linea qualcosa con privilegi di concessione in modo che tutti possano hackerare. Sono abbastanza sicuro che il mio DBA non mi piacerebbe se lo facessi :)

So che a un certo livello questo problema esiste comunque, ma hai livelli di difesa, in particolare per l'eliminazione dei dati, se non si consente all'app Web di gestire gli utenti DB.

Inoltre, ciò impedirebbe qualsiasi utilizzo di connessioni DB raggruppate o riutilizzate.

[1] Quasi tutti direi, ma non cifre per sostenerlo

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.