Domanda:
PGP per l'autenticazione dell'utente è una buona idea?
Sandtler
2020-01-09 01:17:13 UTC
view on stackexchange narkive permalink

Sto creando un sito web che fornisce l'accesso degli utenti. Per questo, sto attualmente cercando buone strategie per gestire l'autenticazione.

Come lo sto facendo adesso

Il mio concetto attuale è modellato su quello che sembra essere il consenso comune giusto adesso. Le password vengono salate con 64 byte da / dev / urandom e quindi hash con 100 round di SHA-512. Dopo ogni round, la password originale viene concatenata al risultato e quindi inserita nel round successivo. Quando un utente vuole accedere, invia le proprie credenziali al server, dove la procedura descritta viene quindi ripetuta (usando lo stesso salt, ovviamente) e confrontata con l'hash nel database.

Questa strategia sembra adeguatamente sicuro per me (per favore correggimi se sbaglio, è fondamentalmente solo il risultato della lettura di molte guide online e della visione di video di YouTube). Tuttavia, penso che abbia un grosso difetto, che è il client che deve inviare la password in chiaro al server. Sì, utilizzo HTTPS naturalmente, ma comunque, se la connessione è stata in qualche modo compromessa per qualsiasi motivo, lo è anche la password.

Il concetto alternativo

Quindi ho pensato a un approccio completamente diverso : utilizzando le chiavi PGP. Quando un utente si iscrive, genera una coppia di chiavi PGP, crittografa la chiave privata utilizzando una password di sua scelta e la invia al server. Quando vogliono accedere di nuovo, il server genera una stringa di caratteri casuali e la crittografa utilizzando la chiave pubblica. La stringa casuale crittografata e la coppia di chiavi vengono quindi inviate al client, che dovrà decrittografarle nuovamente per dimostrare di avere la password della chiave privata.

Questo metodo impedirebbe la trasmissione della password sulla rete e consentirebbe anche cose interessanti come chat crittografate end-to-end tra utenti. L'unico inconveniente che ho riscontrato è che il server deve fornire chiavi private crittografate praticamente a chiunque le richieda, rendendo gli attacchi di forza bruta molto più semplici. Potrei mitigarlo eseguendo un algoritmo di espansione della chiave costoso dal punto di vista computazionale sul lato client e utilizzare il risultato di ciò per crittografare la chiave privata.

Ma ancora non mi fido veramente dell'intera cosa, quindi ho mi piacerebbe sentire il tuo feedback se questa è una buona idea o se dovrei semplicemente restare fedele a come la sto facendo adesso.

EDIT:

Basato su alcuni dei risposte, penso che la mia domanda sia un po 'fuorviante. Il mio requisito è che l'unica cosa che gli utenti debbano fornire per un'autenticazione corretta è il loro nome utente / password e nient'altro, indipendentemente dal dispositivo che stanno utilizzando o dal fatto che abbiano effettuato l'accesso su quel dispositivo in precedenza.

Ciò richiede che il client memorizzi la chiave in qualche modo sul sistema locale (può essere all'interno della memoria locale del browser) che lega la chiave al dispositivo, cioè è molto meno flessibile di una password.Se trovi questa limitazione accettabile o addirittura utile, perché non utilizzare i certificati client che essenzialmente fanno già ciò che stai cercando di reimplementare con PGP?
Potenziale duplicato: https://security.stackexchange.com/questions/72330/why-are-pgp-signatures-not-more-widely-used-as-an-authentication-method e https://security.stackexchange.com/ questions / 135828 / quali-sono-i-potenziali-rischi-derivanti-dall'utilizzo-di-pgp-per-l'accesso-al-sito-web
Il tuo attuale metodo di hashing è abbastanza vicino a PBKDF2.Suggerirei di utilizzare un'effettiva implementazione PBKDF2 da una libreria matura o, se possibile, utilizzare algoritmi di allungamento delle chiavi più robusti, come bcrypt, scrypt o Argon2.Se sei dead-set su SHA-512, puoi continuare a usarlo con PBKDF2, anche se la maggior parte delle librerie sarà impostata su SHA-256 per impostazione predefinita e potrebbe non permetterti di configurare questa opzione.
Ehm, l'accesso tramite certificati TLS è una cosa ... Non c'è bisogno di coinvolgere GPG / PGP, il cui modello "web of trust" non contribuisce qui.
Perché non solo WebAuthn?
Inventare _qualsiasi_ nuova tecnica da soli non è una buona idea.
Altra cosa da sottolineare: farlo in una "web app" ha seri problemi perché il codice viene caricato ogni volta nuovo e non autenticato;se qualcuno riesce a iniettare codice dannoso nel sito, può compromettere il codice che carica la chiave sul client.
Basti pensare a quanto segue: l'utente inserirà la sua password in un sito web, il sito web viene consegnato tramite https, se https è compromesso l'attaccante può semplicemente manipolare il sito web e ottenere direttamente la password.Non appena l'utente inserisce la password, devi fidarti al cento per cento della tua connessione https, quindi trasmetterla non è davvero più rischioso che inserirla nel campo della password.
"La stringa casuale crittografata e la coppia di chiavi vengono quindi inviate al client, che dovrà decrittografarle nuovamente per dimostrare di avere la password della chiave privata".- questo è contrario alla tua ultima modifica.Ora la tua domanda è confusa.
_ "se la connessione è stata in qualche modo compromessa per qualsiasi motivo ..." _ Se un utente malintenzionato può compromettere lo stesso TLS, 1) ha obiettivi molto più preziosi del tuo sito web e 2) qualsiasi forma di autenticazione utente che fai è in gran parte priva di significato
Dovresti usare OPAQUE (vedi https://eprint.iacr.org/2018/163 e https://blog.cryptographyengineering.com/2018/10/19/lets-talk-about-pake/).È un protocollo PAKE che fa qualcosa di molto simile a quello che stai dicendo (memorizzano una coppia di chiavi crittografate sul server), ma evita gli svantaggi del tuo schema.
** 100 ** round di SHA-512 - che è disattivato di * almeno * un fattore di 1000. Vuoi che l'hashing richieda un'apprezzabile frazione di secondo (il più alto possibile senza causare un notevole ritardo all'utente).È necessario eseguire alcuni benchmark, iniziando con un'ipotesi iniziale di 1 milione di iterazioni.Secondo il movimento di utilizzare una funzione di libreria standard per l'hashing della password - e preferibilmente non PBKDF2, ma bcrypt / scrypt / Argon2.
Indipendentemente da qualsiasi problema possa o meno esistere, con varie proposte per risolvere il problema che credi di avere: qual è il tuo modello di minaccia per un aggressore che è in grado di "ficcare il naso" sui tuoi contenuti https ma non ha anche acquisito la capacità diiniettare semplicemente un po 'di keylogging lato client nel modulo di immissione della password?
Credo che molti siti .onion "protetti", come i marketplace, utilizzino questo come secondo passaggio in 2FA.Potrebbe essere utile controllarne alcuni per raccogliere maggiori informazioni sull'implementazione.Reddit ha una lista.
Sette risposte:
averell
2020-01-09 03:47:27 UTC
view on stackexchange narkive permalink

Non dovresti mai provare a proteggere una "vera" applicazione web con uno schema che hai inventato da solo. In quanto tale, non dovremmo discutere gli aspetti pratici su come implementeresti o utilizzeresti effettivamente un tale metodo.

Funzionerà?

Il tuo schema non invia una password via cavo. Quello che salta subito fuori è che invii la chiave privata al server, che non fa mai nulla con essa , senza motivo. Sì, si suppone che sia ancora protetto dalla password, ma perché?

Come altri hanno sottolineato, la chiave privata dovrebbe rimanere con il proprietario.

Anche se si considera la crittografia della password della chiave privata, ci sono (almeno) i seguenti problemi:

  • Distribuire la chiave privata nel proprio schema è essenzialmente lo stesso di rendere pubblico l'hash della password: chiunque può ora eseguire un attacco con dizionario offline contro la password della chiave; e nessuno può fermarlo.
  • Ancora peggio, possono ottenere la chiave per un dato accesso , il che significa che possono controllare se un utente esiste e quindi attaccare la password per il nome utente.

Con una piccola modifica, il tuo schema sarebbe una forma molto semplice di autenticazione con chiave pubblica:

  • Il client crea una coppia di chiavi e invia la chiave pubblica al server
  • Per accedere, il server invia una stringa casuale.
  • Il client firma la stringa e la invia al server.
  • Il server verifica la firma per assicurarsi che il client abbia la chiave privata

Qualcosa di simile in realtà è già possibile in https utilizzando certificati client. La stessa cosa è usata per ssh.

Il meccanismo Challenge-Response menzionato da ThoriumBR è un altro modo di autenticare, sebbene l'implementazione qui descritta presupponga che il server memorizzi la password in chiaro, il che è molto più pericoloso che inviarla su una connessione crittografata.

Sarà "migliore"?

No. Lo scenario da cui vuoi difenderti è presumibilmente che qualcuno entri nella connessione https crittografata. Se presumi che sia così, non solo sarebbero in grado di leggere la password, ma anche di rubare il tuo cookie di sessione e tutti i dati mostrati nella tua sessione. In tal caso, l'attaccante ha già vinto, indipendentemente dal fatto che abbia letto o meno la password.

Potresti ovviamente utilizzare la tua crittografia e autenticazione, ma la domanda è perché pensi che questo essere migliore della connessione https?

Lo scenario realistico non è che qualcuno interrompa la connessione https, è che qualcuno si intrometta nel database del server e cerca di "recuperare" le password in un attacco offline. Questo è ciò da cui la maggior parte degli schemi di autenticazione cerca di difendersi.

Il pericolo con le password non è che siano intercettabili, ma che possono essere indovinate.

Cosa dovresti fare nella vita reale?

Per un'applicazione web "reale", usa un framework consolidato e una libreria di autenticazione ben nota. Non scriverlo da solo, perché è facile sbagliare e molto difficile avere ragione.

Non utilizzare nulla SHA per l'hashing delle password, utilizza una funzione di hashing della password dedicata come bcrypt o PBKDF2 per rendere gli attacchi più difficili (vedi anche questa risposta). Puoi anche utilizzare o aggiungere un meccanismo TOTP per la tua app, che è meglio di una semplice password.

Addendum

Hai aggiunto quanto segue dopo che ho scritto la mia risposta:

Il mio requisito è che l'unica cosa che gli utenti devono fornire per un'autenticazione corretta è il loro nome utente / password e nient'altro, indipendentemente dal dispositivo che stanno utilizzando o dal fatto che abbiano effettuato l'accesso su quel dispositivo prima.

Questo spiega perché vuoi inviare di nuovo la chiave privata al server, anche se non cambia il motivo per cui è una cattiva idea.

Potresti comunque utilizzare un meccanismo di risposta alla sfida, come suggerito da ThoriumBR. Esistono anche meccanismi avanzati di risposta alla sfida come SRP che utilizzano una matematica intelligente per evitare di memorizzare la password sul server.

Tuttavia, tutti questi meccanismi e anche l'hashing lato client (vedi questa risposta), hanno una cosa in comune:

devono eseguire codice sul lato client.

In un'app web, questo può essere solo Javascript inviato dal server. L'implementazione del lato client non è il problema (c'è anche una libreria OpenPGP), ma poiché ti preoccupi della sicurezza della connessione https, hai un altro problema:

Qualsiasi uomo al centro potrebbe quindi semplicemente iniettare codice dannoso lato client per rubare la password, rendendo obsoleto l'intero meccanismo intelligente.

Esiste [TLS-SRP] (https://en.wikipedia.org/wiki/TLS-SRP) che non dipende da Javascript, ma [i principali browser non lo supportano] (https://stackoverflow.com/ questions / 2778629 / tls-srp-in-browsers).Ci sono alcuni problemi con SRP in generale: mancanza di un PBKDF (in alcune implementazioni), mancanza di un debole controllo delle password e, il problema principale, l'interfaccia utente sarebbe brutta (gestita dal browser, come l'autenticazione HTTP di base) onon sicuro (gestito dal sito Web, che consente lo spoofing).WebAuthn sta ottenendo più trazione.
Nit: devi specificare una funzione digest a PBKDF2 (che fondamentalmente la esegue in un ciclo).Assolutamente * consiglierei * SHA-n (n> 1) per la funzione digest.
Capisco chiaramente il tuo punto, quindi ho deciso di scartare qualsiasi progetto di autentica homebrew di fantasia e mi sono appena trasferito a bcrypt, che convenientemente ha già un'implementazione completa su npm.Pensi che un fattore di costo di 12 (che impiega circa 200 ms sulla mia macchina) sia sufficiente?Grazie per la risposta a proposito.
@Sandtler Suggerirei il [Cheat sheet per l'archiviazione delle password OWASP] (https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) - attualmente consiglia un fattore di lavoro di 12 (e l'aggiunta di 1 ogni 18 mesi).
Marcus Müller
2020-01-09 05:42:08 UTC
view on stackexchange narkive permalink

Come hanno detto gli altri, le chiavi private non vengono condivise. punto. Altrimenti, sono chiamate chiavi pubbliche.

Ma: l'accesso crittografico è piuttosto standard. HTTPS supporta che:

Autenticazione utilizzando certificati client HTTPS; e tutti i browser moderni hanno i mezzi integrati per generare le chiavi necessarie quando richiesto.

Il tuo problema è già stato risolto; l'utente genera una coppia di chiavi, ti dà la sua chiave pubblica, mantiene la chiave privata e, al momento della connessione, il server chiede al client di dimostrare di possedere la chiave privata (essenzialmente, lasciandogli firmare qualcosa) .

Fatto !

Altri metodi stabiliti crittograficamente includono almeno un metodo di cui sono a conoscenza:

Accesso singolo tramite ticket Kerberos - questo è estremamente ampio -spread in intranet che utilizzano Active Directory. Ancora una volta, i browser moderni (almeno Edge, Internet Explorer e Firefox) lo supportano immediatamente, sia su Windows che su Linux (non ho provato su OS X o FreeBSD)

Firefox esegue Kerberos solo dopo che il sito è stato aggiunto manualmente a un elenco di siti attendibili per Kerberos (o se la intranet dispone di uno strumento di distribuzione che lo configura per te) per motivi di privacy
@ErikA che generalmente non è corretto, a quanto pare.Posso usare i ticket Kerberos su tutte le mie macchine Linux per iscrivermi alla mia università, appena dopo averli configurati.Nessuno strumento di distribuzione esterno necessario.Potrebbe dipendere dalla configurazione DNS locale (cioè dominio locale consentito per impostazione predefinita, forse?).
È strano, è [documentato] (https://developer.mozilla.org/en-US/docs/Mozilla/Integrated_authentication) che Firefox rifiuti tutti i messaggi SPNEGO per impostazione predefinita, che viene utilizzato per negoziare l'autenticazione Kerberos, e afaik non ci sono eccezioniper la rete locale.Inoltre, Kerberos richiede che SPNEGO funzioni su HTTP (S).E per la mia esperienza personale, certamente non posso usare Kerberos su un'installazione Firefox vuota e devo configurarlo come descritto in quel documento.
Per un rapido test, ho appiattito il mio profilo Firefox qui, e ho aperto la pagina di login, ho cliccato su "Accesso a Windows" (avendo eseguito `kinit user@DOMAIN` dalla shell del mio fedora, buona denominazione, ragazzi), e ha funzionato TM.
@ErikA: Il motivo è che gli attacchi di inoltro Kerberos sono cose reali.samba funzionava esclusivamente in quella modalità molto tempo fa.
Anonymous
2020-01-09 02:12:03 UTC
view on stackexchange narkive permalink

Anche se mi piace l'idea di PGP per il login, non è così che dovrebbe funzionare. La chiave privata deve rimanere sul lato client, sempre e non essere mai condivisa con nessuno. Questa configurazione incoraggia le cattive pratiche e fornisce un'istruzione errata su PGP.

Quello che potresti fare è chiedere agli utenti di caricare la loro chiave pubblica sul server e poi presentare loro un challenge (fondamentalmente, una stringa crittografata) all'accesso, che richiede la chiave privata e ovviamente la passphrase associata ..

Il problema è che poche persone conoscono PGP o hanno una seria inclinazione a usalo. Se puoi farlo, fallo.

"Anche se mi piace l'idea di PGP per il login" .. perché?Per quanto posso vedere, non c'è nulla in PGP che sia utile per questo scenario rispetto al solo utilizzo dei certificati client per l'autenticazione, che è uno standard consolidato.
l'invio di una chiave pubblica o qualsiasi tipo di scambio di chiavi non è vulnerabile agli attacchi man in the middle?che è la principale preoccupazione dell'OP in primo luogo per aggirare la sua attuale forma di scambio di chiavi per un altro tipo!Questo è affrontato nella risposta di Marcus Muller.
ThoriumBR
2020-01-09 02:56:47 UTC
view on stackexchange narkive permalink

Come ha detto Anonymous, la chiave privata deve essere sempre privata. L'invio della chiave privata a qualsiasi entità nega qualsiasi sicurezza fornita dal tuo accesso.

Fondamentalmente, ciò che stai progettando è chiamato autenticazione della risposta di sfida e può essere fatto anche senza una coppia di chiavi:

  • Una parte (il server) genera un token casuale e lo invia all'altra

  • L'altra (il client) concatena la propria password con il token, l'ha hash e invia indietro

  • Il server conosce sia il token che la password, concatena quei valori, l'ha hash e confronta con ciò che il client ha inviato

Se desideri utilizzare una coppia di chiavi, puoi utilizzare la coppia di chiavi per firmare:

  1. Genera un valore casuale R1 e invia all'utente

  2. L'utente riceve R1 e lo firma utilizzando la sua chiave privata

  3. Il server controlla la firma rispetto alla chiave pubblica dell'utente

Questo è tecnicamente facile da fare, ma dubito che la maggior parte degli utenti avrà il know-how necessario per generare una coppia di chiavi e utilizzerà il coppia di chiavi per firmare le cose.

Penso che il tuo primo esempio sia difettoso: richiede che il server memorizzi la password dell'utente in una forma utile a un utente malintenzionato.
Sono d'accordo con Toby, avevi il fatto che il server conosce la password!perché?!
erm410
2020-01-09 22:31:34 UTC
view on stackexchange narkive permalink

Un approccio alternativo che implementa gli stessi concetti è SRP. Ignorando la matematica nel protocollo, l'idea è che quando un utente si iscrive il client genera un verificatore di password che è sufficiente per verificare le credenziali, ma non per agire come loro e lo invia al server per l'archiviazione.

Al momento dell'accesso, le parti si scambiano messaggi in base a valori casuali che alla fine portano al server utilizzando il verificatore memorizzato per garantire che il client abbia la password corretta. I messaggi che il client invia al server sono unidirezionali derivati ​​dalla password e dal valore casuale, quindi la password non viene mai inviata in rete. Il messaggio casuale dal server garantisce che i messaggi dal client siano validi solo per il tentativo di accesso corrente (impedisce a MITM di essere in grado di riprodurre i tentativi di accesso se HTTPS fallisce).

Mentre il protocollo è scoraggiante da implementare , ci sono implementazioni fuori dagli schemi là fuori, ad es AWS Cognito e il suo client JS SDK, quindi è pratico da implementare in qualsiasi app web.

jpa
2020-01-09 19:33:31 UTC
view on stackexchange narkive permalink

Sebbene lo schema descritto nella domanda abbia un problema significativo nell'abilitare attacchi bruteforce offline contro la password, è possibile riprogettarlo senza questa vulnerabilità.

Ad esempio, si può generare private chiave direttamente dalla password. Ciò evita del tutto la necessità di memorizzare le chiavi private: fondamentalmente la password diventa la chiave privata.

Tuttavia, in un'implementazione pratica di un'applicazione web, dovresti eseguire la crittografia in javascript lato client. E se HTTPS come trasporto è danneggiato, è molto probabile che consenta anche di compromettere quel pezzo di javascript, fornendo la password in chiaro.

Un tale schema implementato correttamente sarebbe leggermente più sicuro della pratica standard corrente di testo in chiaro su https + hashing sul lato server. Ma senza una revisione approfondita, è facile commettere errori sottili ma critici nel codice di crittografia e sarebbe meglio spendere sforzi per proteggere altre parti dell'applicazione.

Questo sembra essere esattamente quello che stavo cercando, grazie.Leggerò alcuni articoli su come funziona PBKDF2 in dettaglio e, se si adatta alle mie esigenze, vedrò se esiste un framework maturo che implementa questo meccanismo di autenticazione il più completo possibile al fine di mantenere il mio codice critico per la sicurezza al minimo indispensabile.
Simon Richter
2020-01-09 23:09:20 UTC
view on stackexchange narkive permalink

Questo esiste già.

OpenPGP ha "autenticazione" come possibile utilizzo della chiave e una chiave PGP può essere usata per autenticare una sessione SSH se gpg-agent è usato in modalità ssh-agent. Lo uso quotidianamente come soluzione single sign-on con una smartcard, ma non c'è motivo per cui non funzioni con una chiave normale.

Esistono anche vari plug-in che consentono di firmare i messaggi durante un Handshake TLS utilizzando gpg-agent, consentendo agli utenti di utilizzare la propria chiave PGP per l'autenticazione del certificato client SSL.

Poiché la chiave non lascia mai il dispositivo dell'utente, non è nemmeno necessario generare una nuova chiave, gli utenti possono basta registrarsi con la chiave esistente.

È necessaria un'infrastruttura PKI sufficiente sul lato server per decidere quali chiavi sono valide per quali utenti. La maggior parte dei servizi (ad esempio gitlab, github e launchpad) ti consentono di caricare la tua chiave pubblica in un modulo nell'editor del profilo utente.

Sei un esempio di gitlab e github è per applicazioni che effettivamente utilizzano lo stesso ssh tramite i loro client (git, ecc.) Per l'autenticazione.l'OP non lo considera un'opzione, cerca invece un modo per utilizzare PGP per l'autenticazione basata sul web.
... che hai già citato che viene utilizzato all'interno del processo di handshake TLS stesso.Quindi è corretto considerare che l'invio di un passaggio di testo normale su HTTPS sta già utilizzando una sorta di meccanismo di autenticazione PGP in sé?
@Unicornist, no, solo quando il certificato della sessione TLS viene utilizzato come parte dell'autenticazione, il che significa connettere il browser a gpg-agent.Gitlab / GitHub sono esempi di come iscrivere gli utenti.


Questa domanda e risposta è stata tradotta automaticamente dalla lingua inglese. Il contenuto originale è disponibile su stackexchange, che ringraziamo per la licenza cc by-sa 4.0 con cui è distribuito.
Loading...