Come inviare la password in modo sicuro tramite HTTP?


115

Se in una schermata di accesso l'utente invia un modulo con il suo nome utente e password, la password viene inviata in testo normale (anche con POST, correggimi se sbaglio).

Quindi la domanda è qual è il modo giusto per proteggere l'utente e la sua password da terze parti che potrebbero intercettare i dati di comunicazione?

Sono consapevole che HTTPS è una soluzione al problema, ma esiste un modo per garantire almeno un certo livello di sicurezza utilizzando il protocollo HTTP standard (richiesta POST)? (forse usando javascript in qualche modo)

EDIT Potrei aver tralasciato alcune cose importanti.

Ciò di cui mi occupavo era una pagina, ovvero una pagina di accesso generata da PHP, che ovviamente viene inviata all'utente nella richiesta HTTP GET come file HTML. Non è stata stabilita alcuna connessione (@Jeremy Powel) tra il server e il client, quindi non posso creare tale protocollo di handshaking. E voglio che il processo completo sia trasparente per l'utente: vuole inviare una password, non occuparsi della crittografia.

Grazie.


1
Probabilmente non sarai in grado di farlo senza che il client utilizzi la crittografia, ma l'utente non deve vedere tale processo. Inserisce solo la sua password e il codice generato dal tuo PHP (javascript per esempio) gestisce tutto per te.
Jeremy Powell

13
Il problema che descrivi è il motivo per cui è stato inventato HTTPS. Se invii un segreto al client per crittografare la password, un intercettatore sarà in grado di annusarlo e decrittografare la password durante il viaggio di ritorno.
jnoss

1
Quindi S nel tuo suggerimento potrebbe essere solo password (o nome utente + password combinati in qualsiasi modo), poiché questo è l'unico "segreto" che l'utente possiede. Ho ragione? Quindi la soluzione sarebbe la seguente: - Il server fornisce alla pagina HTML un campo modulo nascosto R - L'utente inserisce la password e prima che la password venga inviata, il javascript calcola H (R, S) e lo invia al server, forse anche usando AJAX - Il server calcola H (R, S) e lo confronta con quello ricevuto e invia una risposta alla richiesta ajax se l'autenticazione è passata - Il javascript reindirizza il browser alla pagina web desiderata
Kornelije Petak

2
@jeremy powell - sebbene ciò che descrivi sia pratica comune, è anche vulnerabile a un intermediario che può annusare il cookie da un'intestazione e impersonare l'utente riutilizzando il cookie. Gli attacchi Man in the middle sono difficili da proteggere a meno che non si utilizzi HTTPS
jnoss

1
Per chi arriva a questa domanda in futuro: DOPO aver effettuato l'accesso, è necessario proteggere anche il cookie di sessione. (Quindi: usare HTTPS è davvero molto più semplice.)
Arjan

Risposte:


66

Usare HTTP con SSL ti renderà la vita molto più facile e potrai stare tranquillo persone molto intelligenti (più intelligenti di me almeno!) Hanno esaminato questo metodo di comunicazione riservata per anni.


14
... e "Ma devo pagare per un certificato SSL !!" non è un reclamo valido, dal momento che puoi ottenerli per $ 30 in questi giorni. I tuoi dati non valgono davvero 30 dollari per essere protetti?
caf

3
Cosa succede se l'host web a cui ti sei iscritto non supporta l'aggiunta di certificati SSL?
Calmarius

89
@Calmarius - poi ti trasferisci su un vero
webhost

3
@BornToCode Questo tecnicamente significa che devi avere un IP dedicato e devi possedere l'hardware del server (o almeno un VPS) per usare HTTPS. I webhost condivisi non possono eseguire HTTPS, a meno che l'intero server non sia protetto con il certificato del proprietario dell'host.
Calmarius

6
i webhost condivisi possono certamente fare https, usando en.wikipedia.org/wiki/Server_Name_Indication
Brian Minton

39

L'autenticazione sicura è un argomento ampio. In poche parole, come menzionato da @ jeremy-powell, preferisci sempre l'invio di credenziali su HTTPS anziché su HTTP. Porterà via molti grattacapi legati alla sicurezza.

I certificati TSL / SSL sono piuttosto economici in questi giorni. In effetti, se non vuoi assolutamente spendere soldi, c'è un letsencrypt.org gratuito - Autorità di certificazione automatizzata.

Puoi fare un ulteriore passo avanti e utilizzare caddyserver.com che chiama letsencrypt in background.

Ora, una volta eliminato HTTPS ...

Non inviare login e password tramite payload POST o parametri GET. Utilizzare invece un'intestazione di autorizzazione (schema di autenticazione di accesso di base), che è costruita come segue:

  • Il nome utente e la password vengono combinati in una stringa separata da due punti, ad esempio: nome utente: password
  • La stringa risultante viene codificata utilizzando la variante RFC2045-MIME di Base64, eccetto non limitato a 76 caratteri / riga.
  • Il metodo di autorizzazione e uno spazio, ad esempio "Basic", vengono quindi inseriti prima della stringa codificata.

fonte: Wikipedia: intestazione di autorizzazione

Potrebbe sembrare un po 'complicato, ma non lo è. Ci sono molte buone librerie là fuori che ti forniranno questa funzionalità fuori dagli schemi.

Esistono alcuni buoni motivi per utilizzare un'intestazione di autorizzazione

  1. È uno standard
  2. È semplice (dopo aver imparato a usarli)
  3. Ti consentirà di accedere a livello di URL, in questo modo: https://user:password@your.domain.com/login(Chrome, ad esempio, lo convertirà automaticamente in Authorizationintestazione)

IMPORTANTE:
come sottolineato da @zaph nel suo commento qui sotto, l'invio di informazioni sensibili come query GET non è una buona idea in quanto molto probabilmente finirà nei log del server.

inserisci qui la descrizione dell'immagine


11
Il problema con l'invio di credenziali (password) come parametri GET è che la coppia utente / password finirà probabilmente nei log del server, il che non è una buona idea. È meglio inviare le credenziali in un POST.
Zaph

Ahh ... per niente. Lo screenshot che stai vedendo è stato modificato per illustrare cosa sta succedendo in un browser. Nel momento in cui premi Invio, il browser convertirà il tuo URL creando Authorizationun'intestazione. Provaci e basta. I registri ricorderanno pulito. E ovviamente se effettui una chiamata dal server (se questo è lo scenario di cui ti preoccupi) dovresti generare l'intestazione a livello di programmazione, ovviamente.
FullStackForger

Non puoi registrare ciò che non puoi vedere. username:password@urldal browser si traduce in: url+ Authorizationintestazione della richiesta. Per quanto riguarda le query GET ... beh, come ho detto, usa l'intestazione Authroziation. È meglio.
FullStackForger

2
Non affronti il ​​punto della domanda: proteggere i dati sensibili dalle intercettazioni man-in-the-middle. L'obiettivo non è trovare un modo alternativo e / o più standardizzato per passare le credenziali, ma proteggerle su un canale insicuro.
Lord of the Goo

3
Va sottolineato che questa soluzione funziona solo se si sta già crittografando la connessione con TLS / SSL. base64 non è una crittografia.
Scozzese

14

È possibile utilizzare uno schema di risposta alla sfida. Supponiamo che il client e il server conoscano entrambi un segreto S. Quindi il server può essere sicuro che il client conosce la password (senza rivelarla):

  1. Il server invia un numero casuale, R, al client.
  2. Il client invia H (R, S) al server (dove H è una funzione hash crittografica, come SHA-256)
  3. Il server calcola H (R, S) e lo confronta con la risposta del client. Se corrispondono, il server sa che il client conosce la password.

Modificare:

C'è un problema qui con la freschezza di R e il fatto che HTTP è senza stato. Questo può essere gestito facendo in modo che il server crei un segreto, chiamalo Q, che solo il server conosce . Quindi il protocollo funziona in questo modo:

  1. Il server genera un numero casuale R. Quindi invia al client H (R, Q) (che non può essere contraffatto dal client).
  2. Il client invia R, H (R, Q) e calcola H (R, S) e lo rimanda tutto al server (dove H è una funzione hash crittografica, come SHA-256)
  3. Il server calcola H (R, S) e lo confronta con la risposta del client. Quindi prende R e calcola (di nuovo) H (R, Q). Se la versione del client di H (R, Q) e H (R, S) corrisponde al ricalcolo del server, il server considera il client autenticato.

Da notare, poiché H (R, Q) non può essere contraffatto dal client, H (R, Q) funge da cookie (e potrebbe quindi essere implementato effettivamente come cookie).

Un'altra modifica:

La precedente modifica al protocollo non è corretta poiché chiunque abbia osservato H (R, Q) sembra essere in grado di riprodurlo con l'hash corretto. Il server deve ricordare quali R non sono più fresche. Sto scrivendo questa risposta in modo che voi ragazzi possiate modificare questa e elaborare qualcosa di buono.


+1 - dovrai calcolare la risposta lato client con javascript (o Flash / Silverlight / ecc.)
orip

10
Non ferma l'uomo nel mezzo o gli attacchi di imitazione. Ad esempio tramite wifi. Sembra che questo darà solo un falso senso di sicurezza, IMO.
Tom Hawtin - tackline

2
Ciò protegge dagli attacchi passivi, ma un Man in the Middle può comunque attaccare.
Douglas Leeder

7
Inoltre richiede al server di conoscere la password originale.
Douglas Leeder

3
Non reinventare la crittografia! (in produzione)
bryanph

11

Se il tuo webhost lo consente o dovrai gestire dati sensibili, utilizza HTTPS, punto. (È spesso richiesto dalla legge afaik).

Altrimenti se vuoi fare qualcosa tramite HTTP. Farei qualcosa di simile.

  1. Il server incorpora la sua chiave pubblica nella pagina di accesso.
  2. Il client compila il modulo di accesso e fa clic su Invia.
  3. Una richiesta AJAX ottiene il timestamp corrente dal server.
  4. Lo script lato client concatena le credenziali, il timestamp e un salt (hash da dati analogici, ad es. Movimenti del mouse, eventi di pressione dei tasti), crittografa utilizzando la chiave pubblica.
  5. Invia l'hash risultante.
  6. Il server decrittografa l'hash
  7. Controlla se il timestamp è abbastanza recente (consente solo una breve finestra di 5-10 secondi). Rifiuta il login se il timestamp è troppo vecchio.
  8. Memorizza l'hash per 20 secondi. Rifiuta lo stesso hash per l'accesso durante questo intervallo.
  9. Autentica l'utente.

In questo modo la password è protetta e lo stesso hash di autenticazione non può essere riprodotto.

Informazioni sulla sicurezza del token di sessione. È un po 'più difficile. Ma è possibile rendere un po 'più difficile riutilizzare un token di sessione rubato.

  1. Il server imposta un cookie di sessione aggiuntivo che contiene una stringa casuale.
  2. Il browser restituisce questo cookie alla richiesta successiva.
  3. Il server controlla il valore nel cookie, se è diverso distrugge la sessione, altrimenti va tutto bene.
  4. Il server imposta nuovamente il cookie con un testo diverso.

Quindi, se il token di sessione è stato rubato e una richiesta viene inviata da qualcun altro, alla successiva richiesta dell'utente originale la sessione verrà distrutta. Quindi, se l'utente naviga attivamente nel sito, facendo clic spesso sui collegamenti, il ladro non andrà lontano con il token rubato. Questo schema può essere rafforzato richiedendo un'altra autenticazione per le operazioni sensibili (come l'eliminazione dell'account).

EDIT: Si prega di notare che questo non impedisce gli attacchi MITM se l'aggressore imposta la propria pagina con una chiave pubblica diversa e le richieste proxy al server. Per proteggersi da ciò, la chiave pubblica deve essere bloccata nella memoria locale del browser o all'interno dell'app per rilevare questo tipo di trucchi.

Informazioni sull'implementazione: RSA è probabilmente all'algoritmo più noto, ma è piuttosto lento per chiavi lunghe. Non so quanto sarebbe veloce un'implementazione PHP o Javascript di. Ma probabilmente ci sono algoritmi più veloci.


In questo caso la password è davvero protetta? Qualcuno non potrebbe fiutare ciò che viene inviato e decrittografarlo utilizzando la chiave pubblica e quindi aggiornare semplicemente il timestamp quando lo useranno in seguito? Mi sto perdendo qualcosa?
michaellindahl

La crittografia asimmetrica @michaellindahl significa che solo la chiave privata, che non lascia mai il server, può essere utilizzata per decrittografare le cose. Le chiavi pubbliche possono essere utilizzate solo per crittografare.
Dan Pantry

2
Un computer tra il browser e il server potrebbe cambiare la chiave pubblica nella pagina di accesso.
Antti

Grazie per aver condiviso i tuoi metodi, ho trovato tutto molto interessante. Il timestamp aggiunto sull'invio di credenziali è una buona presa! Una domanda sull'uso di un cookie di sessione extra il cui valore è una stringa casuale: è come un token solo per la richiesta successiva?
Victor

4

Vorrei utilizzare un sistema di scambio di chiavi Diffie-Hellman lato server e lato client con AJAX o più invii di moduli (consiglio il primo), anche se non vedo alcuna buona implementazione su Internet. Ricorda che una libreria JS può sempre essere danneggiata o modificata da MITM. L'archiviazione locale può essere utilizzata per combattere questo, in una certa misura.


4

È possibile utilizzare SRP per utilizzare password sicure su un canale non protetto. Il vantaggio è che anche se un utente malintenzionato rileva il traffico o compromette il server, non può utilizzare le password su un server diverso. https://github.com/alax/jsrp è una libreria javascript che supporta password sicure su HTTP nel browser o lato server (tramite nodo).


1

HTTPS è così potente perché utilizza la crittografia asimmetrica. Questo tipo di crittografia non solo ti consente di creare un tunnel crittografato, ma puoi verificare che stai parlando con la persona giusta e non con un hacker.

Ecco il codice sorgente Java che utilizza la crittografia asimmetrica RSA (utilizzata da PGP) per comunicare: http://www.hushmail.com/services/downloads/


0

puoi usare ssl per il tuo host c'è un progetto gratuito per ssl come letsencrypt https://letsencrypt.org/


2
Controlla la terza frase in questione. (Inoltre, leggi sempre altre risposte per assicurarti di non aggiungere un duplicato meno dettagliato.)
Nathan Tuggy

0

L'uso di https sembra l'opzione migliore qui (i certificati non sono così costosi al giorno d'oggi). Tuttavia, se http è un requisito, è possibile utilizzare una codifica: codificarla sul lato server e decriptarla nel browser dell'utente (inviare la chiave separatamente).

Lo abbiamo utilizzato durante l'implementazione di safevia.net - la codifica viene eseguita sui lati dei client (mittente / destinatario), quindi i dati degli utenti non sono disponibili sulla rete né sul livello del server.

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.