Se riesci a decodificare JWT, come sono sicuri?


302

Se ottengo un JWT e posso decodificare il payload, come è sicuro? Non potrei semplicemente estrarre il token dall'intestazione, decodificare e modificare le informazioni dell'utente nel payload e rispedirle con lo stesso segreto codificato corretto?

So che devono essere sicuri, ma vorrei davvero capire le tecnologie. Cosa mi sto perdendo?


2
md5('original messaged' + secret) != md5('changed message' + secret)quindi se qualcuno modifica il messaggio lo puoi rilevare
Pithikos

vero per un caso ideale, tuttavia, md5 ha delle collisioni. @Pithikos
Yash Kumar Verma

@YashKumarVerma sì, è solo per dimostrarne l'essenza poiché tutti conoscono md5.
Pithikos,

1
@ user1955934 è codificato in base64, NON crittografato. Puoi semplicemente decodificarlo con qualsiasi decodificatore base64.
Pithikos,

1
quindi il client dovrà inviare sia l'hash sia il token jwt? e più tardi sul lato server proveranno a eseguire l'hashing del token jwt usando secret e confrontarlo con l'hash?
user1955934

Risposte:


387

I JWT possono essere firmati, crittografati o entrambi. Se un token è firmato, ma non crittografato, tutti possono leggerne il contenuto, ma quando non si conosce la chiave privata, non è possibile modificarlo. Altrimenti, il destinatario noterà che la firma non corrisponderà più.

Rispondi al tuo commento: non sono sicuro di aver compreso il tuo commento nel modo giusto. Giusto per essere sicuri: conosci e comprendi le firme digitali? Spiegherò brevemente una variante (HMAC, che è simmetrica, ma ce ne sono molte altre).

Supponiamo che Alice voglia inviare un JWT a Bob. Entrambi conoscono un segreto condiviso. Mallory non conosce questo segreto, ma vuole interferire e cambiare il JWT. Per evitarlo, Alice calcola Hash(payload + secret)e lo aggiunge come firma.

Quando riceve il messaggio, Bob può anche calcolare Hash(payload + secret)per verificare se la firma corrisponde. Se tuttavia, Mallory cambia qualcosa nel contenuto, non è in grado di calcolare la firma corrispondente (che sarebbe Hash(newContent + secret)). Non conosce il segreto e non ha modo di scoprirlo. Ciò significa che se cambia qualcosa, la firma non corrisponderà più e Bob semplicemente non accetterà più il JWT.

Supponiamo che invii a un'altra persona il messaggio {"id":1}e lo firmo con Hash(content + secret). (+ è solo una concatenazione qui). Io uso la funzione SHA256 Hash, e la firma ottengo è: 330e7b0775561c6e95797d4dd306a150046e239986f0a1373230fda0235bda8c. Ora è il tuo turno: gioca il ruolo di Mallory e prova a firmare il messaggio {"id":2}. Non puoi perché non sai quale segreto ho usato. Se suppongo che il destinatario conosca il segreto, PUO 'calcolare la firma di qualsiasi messaggio e verificarne la correttezza.


8
Quindi la firma viene modificata quando viene modificato il payload? Avevo l'impressione che il token fosse nel formato [header]. [Payload]. [Firma] la firma è calcolata dalla combinazione del payload e del segreto? Se così fosse, un payload con un ID diverso non sarebbe lo stesso per quel segreto? Ad esempio, se i dati fossero {id: 1} e utilizzati per calcolare la parte della firma del token con il segreto, ciò non significherebbe che {id: 2} sarebbe valido per l'utente 2 e quindi l'utente 1 potrebbe cambiare id a 2 e il token sarebbe lo stesso?
PixMach il

7
Ti ho fatto un esempio per rendere le cose ancora più chiare, ma non ti spiegherò l'intero concetto di firme digitali e HMAC. Per favore, leggi queste cose, c'è molto materiale che lo spiega.
Misch

11
Oh capisco adesso. Non so perché mi mancasse l'idea che l'hash segreto non fosse corretto quando si modificava il payload perché l'hash segreto avrebbe dovuto essere ricalcolato. Per qualche ragione stavo ancora pensando che fosse indipendente. Quest'ultimo pezzo l'ha davvero perforato per me. Grazie per avermi guidato.
PixMach,

30
Ho una domanda in merito. Cosa impedisce a qualcuno di impersonare Alice con il JWT copiato?
Morrowless,

25
Se qualcuno ha il JWT può impersonare Alice. Quindi devi stare attento a come lo memorizzi e lo invii. Dovresti anche impostare una scadenza per questo nel payload. In questo modo se qualcuno ruba il JWT hanno un periodo di tempo limitato per usarlo. Dai
Geraint Anderson il

134

Puoi andare a jwt.io, incollare il token e leggere il contenuto. Questo è stonante per molte persone inizialmente.

La risposta breve è che JWT non si occupa della crittografia. Si preoccupa della convalida. Vale a dire, può sempre ottenere la risposta per "Hai manipolato il contenuto di questo token"? Ciò significa che la manipolazione dell'utente del token JWT è inutile perché il server riconoscerà e ignorerà il token. Il server aggiunge una firma in base al payload durante l'emissione di un token al client. Successivamente verifica il payload e la firma corrispondente.

La domanda logica è: qual è la motivazione per non occuparsi di contenuti crittografati?

  1. Il motivo più semplice è perché presume che questo sia un problema risolto per la maggior parte. Se ad esempio hai a che fare con un client come il browser web, puoi archiviare i token JWT in un cookie che non è secure(non trasmesso via HTTP, solo tramite HTTPS) e httpOnly(non può essere letto da Javascript) e parla al server un canale crittografato (HTTPS). Una volta che sai di avere un canale sicuro tra il server e il client, puoi scambiare JWT in modo sicuro o qualsiasi altra cosa tu voglia.

  2. Questo semplifica le cose. Una semplice implementazione semplifica l'adozione, ma consente anche a ciascun layer di fare ciò che fa meglio (lascia che HTTPS gestisca la crittografia).

  3. JWT non è pensato per archiviare dati sensibili. Una volta che il server riceve il token JWT e lo convalida, è libero di cercare l'ID utente nel proprio database per ulteriori informazioni per quell'utente (come autorizzazioni, indirizzo postale, ecc.). Ciò mantiene le dimensioni ridotte di JWT ed evita la dispersione involontaria di informazioni perché tutti sanno di non mantenere i dati sensibili in JWT.

Non è troppo diverso da come funzionano i cookie stessi. I cookie spesso contengono payload non crittografati. Se stai usando HTTPS, allora è tutto a posto. In caso contrario, è consigliabile crittografare i cookie sensibili stessi. Non farlo significherà che è possibile un attacco man-in-the-middle: un server proxy o un ISP legge i cookie e poi li riproduce in seguito fingendo di essere te. Per motivi simili, JWT dovrebbe sempre essere scambiato su un livello sicuro come HTTPS.


4
Ricordalo! JWT dovrebbe sempre essere scambiato su un livello sicuro come HTTPS
codemirror

Ma se JWT è sicuro solo su HTTPS, perché non inviare semplicemente il payload? POST -> nome utente, password. È ancora crittografato giusto?
GeekPeek,

@GeekPeek per questo dovresti leggere le basi di JWT ma Session Auth come menzioni spesso è tutto ciò di cui hai bisogno. JWT offre alcuni altri vantaggi ma rende alcuni compromessi webskeleton.com/webdev/2019/10/22/…
aleemb

17

I contenuti di un token web json (JWT) non sono intrinsecamente sicuri, ma è presente una funzionalità integrata per la verifica dell'autenticità del token. Un JWT è composto da tre hash separati da punti. Il terzo è la firma. In un sistema a chiave pubblica / privata, l'emittente firma la firma del token con una chiave privata che può essere verificata solo dalla chiave pubblica corrispondente.

È importante comprendere la distinzione tra emittente e verificatore. Il destinatario del token è responsabile della sua verifica.

Esistono due passaggi fondamentali nell'uso sicuro di JWT in un'applicazione Web: 1) inviarli su un canale crittografato e 2) verificare la firma immediatamente dopo averla ricevuta. La natura asimmetrica della crittografia a chiave pubblica rende possibile la verifica della firma JWT. Una chiave pubblica verifica che un JWT sia stato firmato dalla chiave privata corrispondente. Nessun'altra combinazione di chiavi può eseguire questa verifica, evitando così tentativi di rappresentazione. Segui questi due passaggi e possiamo garantire con certezza matematica l'autenticità di un JWT.

Altre letture: in che modo una chiave pubblica verifica una firma?


2

Discutiamo fin dall'inizio:

JWT è un approccio molto moderno, semplice e sicuro che si estende ai token Web Json. I token Web Json sono una soluzione senza stato per l'autenticazione. Quindi non è necessario memorizzare alcuno stato di sessione sul server, il che è ovviamente perfetto per le API riposanti. Le API riposanti dovrebbero essere sempre senza stato e l'alternativa più utilizzata all'autenticazione con JWT è semplicemente memorizzare lo stato di accesso dell'utente sul server utilizzando le sessioni. Ma ovviamente non segue il principio secondo cui le API riposanti dovrebbero essere apolidi ed è per questo che soluzioni come JWT sono diventate popolari ed efficaci.

Quindi ora sappiamo come funziona l'autenticazione con i token Web Json. Supponendo che abbiamo già un utente registrato nel nostro database. Quindi il client dell'utente inizia facendo una richiesta post con il nome utente e la password, l'applicazione quindi controlla se l'utente esiste e se la password è corretta, quindi l'applicazione genererà un token Json Web univoco solo per quell'utente.

Il token viene creato utilizzando una stringa segreta che è memorizzato su un server . Successivamente, il server invia quindi quel JWT al client che lo memorizzerà in un cookie o nella memoria locale. inserisci qui la descrizione dell'immagine

Proprio in questo modo, l'utente è autenticato e sostanzialmente connesso alla nostra applicazione senza lasciare alcuno stato sul server.

Quindi il server in realtà non sa quale utente ha effettivamente effettuato l'accesso, ma ovviamente l'utente sa che ha effettuato l'accesso perché ha un token Json Web valido che è un po 'come un passaporto per accedere a parti protette dell'applicazione.

Quindi, solo per essere sicuro che tu abbia avuto l'idea. Un utente ha effettuato l'accesso non appena ottiene il suo esclusivo token Json Web valido che non viene salvato in nessun punto del server. E quindi questo processo è quindi completamente apolide.

Quindi, ogni volta che un utente desidera accedere a un percorso protetto come i dati del suo profilo utente, ad esempio. Invia il suo token Web Json insieme a una richiesta, quindi è un po 'come mostrare il suo passaporto per ottenere l'accesso a quella rotta.

Una volta che la richiesta ha colpito il server, la nostra app verificherà quindi se il token Web Json è effettivamente valido e se l'utente è davvero chi dice di essere, allora i dati richiesti verranno inviati al client e, in caso contrario, ci sarà essere un errore che dice all'utente che non gli è permesso accedere a quella risorsa. inserisci qui la descrizione dell'immagine

Tutta questa comunicazione deve avvenire tramite https, quindi Http crittografato sicuro per impedire a chiunque di accedere a password o token Web Json. Solo allora abbiamo un sistema davvero sicuro.

inserisci qui la descrizione dell'immagine

Quindi un token Json Web sembra la parte sinistra di questo screenshot che è stato preso dal debugger JWT su jwt.io In sostanza, è una stringa di codifica composta da tre parti. L'intestazione, il payload e la firma Ora l'intestazione è solo alcuni metadati relativi al token stesso e il payload sono i dati che possiamo codificare nel token, tutti i dati che realmente desideriamo. Quindi, più dati vogliamo codificare qui, più grande è il JWT. Ad ogni modo, queste due parti sono solo testo semplice che verrà codificato, ma non crittografato.

Quindi chiunque sarà in grado di decodificarli e di leggerli , qui non possiamo archiviare dati sensibili. Ma questo non è affatto un problema perché nella terza parte, quindi nella firma, è dove le cose diventano davvero interessanti. La firma viene creata utilizzando l'intestazione, il payload e il segreto che viene salvato sul server.

E l'intero processo viene quindi chiamato firma del token Web Json . L'algoritmo di firma accetta l'intestazione, il payload e il segreto per creare una firma univoca. Quindi solo questi dati e il segreto possono creare questa firma, va bene? Quindi, insieme all'intestazione e al payload, queste firme formano il JWT, che viene quindi inviato al client. inserisci qui la descrizione dell'immagine

Una volta che il server riceve un JWT per concedere l'accesso a un percorso protetto, deve verificarlo per determinare se l'utente è realmente chi afferma di essere. In altre parole, verificherà se nessuno ha modificato l'intestazione e i dati del payload del token. Di nuovo, questo passaggio di verifica verificherà se nessuna terza parte ha effettivamente modificato l'intestazione o il payload del token Web Json.

Quindi, come funziona questa verifica? Bene, in realtà è abbastanza semplice. Una volta ricevuto il JWT, la verifica prenderà la sua intestazione e il suo payload e, insieme al segreto ancora salvato sul server, fondamentalmente creerà una firma di prova.

Ma la firma originale che è stata generata quando è stato creato il JWT è ancora nel token, giusto? E questa è la chiave per questa verifica. Perché ora tutto ciò che dobbiamo fare è confrontare la firma del test con la firma originale. E se la firma del test è la stessa della firma originale, significa che il payload e l'intestazione non sono stati modificati. inserisci qui la descrizione dell'immagine

Perché se fossero stati modificati, la firma del test avrebbe dovuto essere diversa. Pertanto, in questo caso in cui non vi è stata alcuna modifica dei dati, possiamo quindi autenticare l'utente. E ovviamente, se le due firme sono effettivamente diverse, allora significa che qualcuno ha manomesso i dati. Di solito, provando a modificare il payload. Ma quella terza parte che manipola il payload non ha ovviamente accesso al segreto, quindi non può firmare il JWT. Quindi la firma originale non corrisponderà mai ai dati manipolati. E quindi, la verifica fallirà sempre in questo caso. E questa è la chiave per far funzionare l'intero sistema. È la magia che rende JWT così semplice, ma anche estremamente potente.


1

Solo il privateKey di JWT, che si trova sul tuo server, decodificherà il JWT crittografato. Chi conosce PrivateKey sarà in grado di decrittografare il JWT crittografato.

Nascondi privateKey in una posizione sicura nel tuo server e non dire mai a privateKey.


1
I JWT non sono sempre crittografati. Possono essere firmati, crittografati, firmati quindi crittografati o crittografati quindi firmati.
csauve

0

Per le persone che non possono permettersi costose query sul database proprio come me, un'opzione per mantenere i dati sensibili (privilegi utente ecc.) È che quando si genera il JWT è possibile crittografare questi dati e collegarli al token JWT. (Conserva la chiave di crittografia nel back-end)

Quando si desidera leggere le informazioni riservate, è possibile inviare il token JWT al back-end, decodificarlo e recuperare le informazioni. In questo modo, non è necessario eseguire ricerche nel DB o avere le informazioni sensibili nude nel frontend tramite token JWT


-1

Suggerirei di dare un'occhiata a JWE usando algoritmi speciali che non sono presenti in jwt.io per decifrare

Link di riferimento: https://www.npmjs.com/package/node-webtokens

jwt.generate('PBES2-HS512+A256KW', 'A256GCM', payload, pwd, (error, token) => {
  jwt.parse(token).verify(pwd, (error, parsedToken) => {
    // other statements
  });
});

Questa risposta potrebbe essere troppo tardi o potresti aver già scoperto la strada, ma ho pensato che sarebbe stata utile anche per te e per gli altri.

Un semplice esempio che ho creato: https://github.com/hansiemithun/jwe-example

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.