Che cos’è una chiave di firma?
Nel contesto di OpenID Connect (OIDC) , una chiave di firma è solitamente una coppia di chiavi asimmetriche utilizzata per firmare e verificare JSON Web Tokens (JWTs) . I provider OpenID utilizzano le chiavi di firma per firmare token come ID token e access token per garantire la loro integrità e autenticità.
Sebbene il concetto di chiavi di firma possa essere più ampio, ci concentreremo su come vengono utilizzate in OIDC per proteggere i token. Altri casi d’uso includono la firma di email, documenti e pacchetti software, che possono derivare dagli stessi principi.
Esempio: firma di un ID token
Quando un utente si autentica con un provider OpenID, il provider emette un ID token che contiene informazioni sull’utente ( claims ) ed è firmato dalla chiave di firma del provider. Poiché l’ID token è un JWT, è composto da tre parti: intestazione, payload e firma.
1. Intestazione
Supponiamo che l’intestazione sia:
{
"alg": "ES384",
"typ": "JWT"
}
Il JSON indica che l’ID token è firmato utilizzando l’algoritmo
ECDSA con la curva P-384. Il campo typ
specifica che il tipo di token è JWT.
2. Payload
Il payload contiene informazioni di base sull’utente:
{
"sub": "1234567890",
"name": "Alice"
}
Il sub
claim è l’identificatore univoco dell’utente, e name
è il loro nome visualizzato.
3. Firma del token
Secondo il formato JWT, l’intestazione e il payload devono essere codificati in Base64URL e concatenati con un .
per la firma:
{{header}}.{{payload}}
In questo caso, il valore sarebbe:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0
Supponiamo che il provider OpenID utilizzi la seguente chiave privata per firmare il token:
-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBW9PDXInlNT2hjOtQr
g4pkVkyJsKia33dHrsbOG4Z77pfYN7SYZCHh9YdLXTTKinehZANiAAQX/FB1s6Gj
YnDSGCY08PRUAQ8CCRCt8Ph/VDHfLj1xSbrjp8wFf0NjH7jcfNebpV1fvu4XKbP3
Ro7h0G6elN1TMsVECJPv4ieDNkYOsgT4UboJypC5E/rmvrlJTMM6Y/k=
-----END PRIVATE KEY-----
Per firmare il token, il provider OpenID deve utilizzare la chiave privata per generare una firma tramite:
signature = sign(header + '.' + payload, private_key)
Quindi la firma codificata in Base64URL è:
Cjy6A_FHnwQBP0hRawoGTkRy8m8o0Ncc1q4BeyxYr0fxhKYmJJinIWZPXJdaAXRO9wOFuH2-UML2yWHjot_LnCPO6362asMvgNkEJMZ6UtqyOPlsCOJ7voTPOCT6sYu2
4. Assemblare il JWT
Infine, il provider OpenID assembla il JWT concatenando l’intestazione, il payload e la firma con .
:
{{header}}.{{payload}}.{{signature}}
In questo caso, l’ID token sarebbe:
eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0.Cjy6A_FHnwQBP0hRawoGTkRy8m8o0Ncc1q4BeyxYr0fxhKYmJJinIWZPXJdaAXRO9wOFuH2-UML2yWHjot_LnCPO6362asMvgNkEJMZ6UtqyOPlsCOJ7voTPOCT6sYu2
L’ID token è ora pronto per essere inviato al Client per ulteriori elaborazioni.
5. Verifica del token
Quando il client riceve l’ID token, può verificare la firma utilizzando la chiave pubblica del provider OpenID. Di solito, la chiave pubblica è resa disponibile tramite l’endpoint Scoperta di OpenID Connect (OIDC) (jwks_uri
) nel formato di un Set di Chiavi Web JSON (JWKS) .
Per questo esempio, la chiave pubblica è:
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEF/xQdbOho2Jw0hgmNPD0VAEPAgkQrfD4
f1Qx3y49cUm646fMBX9DYx-43HzXm6VdX77uFymz90aO4dBunpTdUzLFRAiT7+In
gzZGDrIE+FG6CcqQuRP65r65SUzDOmP5
-----END PUBLIC KEY-----
E il valore JWK corrispondente è:
{
"kty": "EC",
"crv": "P-384",
"x": "F_xQdbOho2Jw0hgmNPD0VAEPAgkQrfD4f1Qx3y49cUm646fMBX9DYx-43HzXm6Vd",
"y": "X77uFymz90aO4dBunpTdUzLFRAiT7-IngzZGDrIE-FG6CcqQuRP65r65SUzDOmP5"
}
Ora, il client può verificare la firma utilizzando la chiave pubblica.
Scegliere l’algoritmo giusto
Esistono vari algoritmi disponibili per firmare i JWT:
- Algoritmi simmetrici: HMAC con SHA-family (ad esempio, HS256, HS384, HS512) è un algoritmo simmetrico che utilizza la stessa chiave sia per la firma che per la verifica. Non è raccomandato nella maggior parte dei casi poiché la chiave segreta deve essere condivisa tra le parti.
- Algoritmi asimmetrici: RSA (ad esempio, RS256, RS384, RS512) e ECDSA (ad esempio, ES256, ES384, ES512) sono algoritmi asimmetrici che utilizzano una coppia di chiavi: una chiave privata per la firma e una chiave pubblica per la verifica.
- RSA è ampiamente utilizzato e supportato da molte librerie e piattaforme. Tuttavia, ha una dimensione della chiave e della firma molto più grande rispetto a ECDSA.
- ECDSA è più performante e genera firme più piccole, rendendolo una scelta migliore per ambienti con risorse limitate. Poiché è meno comune, assicurati che la tua piattaforma lo supporti.
ECDSA dovrebbe essere la scelta preferita per le nuove applicazioni grazie ai suoi benefici in termini di prestazioni e sicurezza.
Altri scenari di chiavi di firma
Sebbene l’esempio sopra si concentri sugli ID token in OIDC, il concetto di chiave di firma è ampiamente utilizzato in vari scenari, come la firma di email, documenti e pacchetti software. I principi chiave rimangono gli stessi:
- Per le chiavi simmetriche, la stessa chiave viene utilizzata sia per la firma che per la verifica. Questo è adatto per scenari in cui le parti possono condividere la chiave in modo sicuro, o c’è un’unica entità responsabile sia della firma che della verifica.
- Per le chiavi asimmetriche, una chiave privata viene utilizzata per la firma e una chiave pubblica corrispondente viene utilizzata per la verifica. Questo è adatto per la maggior parte degli scenari in cui le parti di firma e verifica sono entità diverse.