Démonstration de la preuve de possession

Traitement des jetons au porteur compromis

Les jetons OAuth Bearer sont utilisés pour accéder aux ressources protégées. Ils sont souvent utilisés pour offrir une preuve suffisante pour obtenir l'accès par l'utilisation de champs d'application ou de détails plus fins dans les demandes, comme authorization_details (Ref : Rich authorization request ). Cela signifie que si un acteur ou un système non autorisé accède au jeton porteur, il peut usurper l'identité de l'utilisateur (ou du système) et accéder aux ressources protégées. Le serveur de ressources n'a aucun moyen de vérifier que l'expéditeur du jeton de support est légitime tant que le jeton est valide.

Une solution consiste à exiger l'utilisation de jetons de preuve de possession qui permettent à un serveur de ressources de vérifier que le jeton de support est utilisé par un client légitime. Les jetons d'accès liés à un certificat constituent l'une de ces méthodes. La démonstration de la preuve de possession au niveau de la couche applicative(DPoP est une autre approche qui convient mieux aux clients qui ne peuvent pas utiliser TLS mutuel, comme les applications à page unique qui n'ont pas de backend.

📘

Note

La démonstration de la preuve de possession dans la couche application DPoP ) est un projet de norme. Toutefois, elle a été mise en œuvre dans IBM Security Verify en raison des avantages évidents qu'elle présente et en prévision de Financial Grade API (FAPI) 2.0

Jetons DPoP-bound

Les jetons DPoP-bound sont liés à une clé privée générée par le client et détenue par ce dernier. La clé privée ne doit pas être divulguée et doit être stockée de manière à ce que le code de l'application ne puisse pas accéder à ses paramètres. Sur les navigateurs, par exemple, cela peut être réalisé à l'aide de SubtleCrypto, où la clé générée est marquée comme non extractible et empêche le code de l'application JavaScript d'exporter les paramètres de la clé privée à partir du navigateur.

Un certain nombre d'étapes facultatives peuvent être exécutées dans un flux qui demande un jeton DPoP-bound. Toutefois, par souci de simplicité, les étapes ci-dessous sont exécutées sur le client avant d'appeler le point de terminaison du jeton sur le serveur d'autorisation OAuth.

  1. Générer une paire de clés
// Generates a key pair. The private key is marked non-extractable to prevent
// any application code from exporting private key parameters.
async function generateKey() {
  const generatedKeyPair: CryptoKeyPair = await crypto.subtle.generateKey({
        name: 'RSASSA-PKCS1-v1_5',
        modulusLength: 4096,
        publicExponent: new Uint8Array([1, 0, 1]),
        hash: 'SHA-256',
    },
    false,
    ['sign', 'verify']
  );

  return generatedKeyPair;
}
  1. Créer une preuve DPoP: La preuve DPoP est un jeton Web JSON qui intègre les paramètres publics de la clé de signature au format JWK dans l'en-tête JWT et qui est signé par la clé privée générée à l'étape 1. Les revendications standard, telles que l'heure d'émission ( iat ), l'expiration ( exp ) et l'identifiant JWT ( jti ), sont incluses. En outre, la preuve doit contenir la méthode HTTP ( htm ) et l' URL HTTP ( htu ) du point de terminaison du jeton
{
  "alg": "RS256",
  "typ": "dpop+jwt",
  "jwk": {
    "kty": "RSA",
    "n": "o5Fiw7GSdTDrO61ivks7KM2M7bLar4HF9DWLcIRDGcQqNu0aRMkWLD4QEBtqkyV8Uu30WZ4g8sZxgSGLVoSH9JGc270vWqtA0fYx7AhFi1JPHM-v3Kz3PtLHCIXTRFi-Cj-uDNn31RMduMVevtjmuPz99_qvQU4lDGhQsyAjONNEjYQ5wJp_iYVYPXXRpP3rGg2avoTrsvtFzEABecmIKWGh556M7qSFwdboIUKG-Q6DdBYD9aq3tm0A8JiFATA3RONVF8dSIPl1dfUkwRsosZI2Fr-OT51x6J5f0Kz8J6DUj_UHr0ecwtn25sLZHEN-fCxZ1LeEK-ZeUgIrxZLagw",
    "e": "AQAB",
    "kid": "HjFAbEgNeDnFbLWHh3cR3B63wI2U0xm0ZTuIV_8I8EU"
  }
}
{
  "jti": "e63dcda8-f374-4701-aa94-55664c973b0e",
  "iat": 1678798289,
  "exp": 1678800089,
  "htm": "POST",
  "htu": "https://harbinger.verify.ibm.com/oauth2/token"
}
  1. Faire la demande de jeton : Dans le cadre de cette demande, la preuve du DPoP est incluse dans l'en-tête dpop.

  2. Si la preuve DPoP est valide, le serveur d'autorisation IBM Security Verify ) émet un jeton de type "DPoP". Dans le cadre de ce processus, l'empreinte est générée à partir du site jwk intégré dans la preuve DPoP et ajoutée à l'autorisation accordée dans le cadre de la demande de "confirmation" ( cnf ). Elle est ensuite mise à disposition dans le cadre de la réponse d'introspection du jeton ou incorporée dans un jeton d'accès formaté JWT.

Voici un exemple de réponse d'introspection. La charge utile comprend la demande de confirmation.

{
  "active": true,
  "aud": [
      "177cb3ec-b112-4c29-8b08-94717f7bc4b6"
  ],
  "client_id": "177cb3ec-b112-4c29-8b08-94717f7bc4b6",
  "cnf": {
      "jkt": "PJ4wWW_nkvnKbKHPrgyjr7DiCBrTL4JbwDGBlBFKOCw"
  },
  "exp": 1678945818,
  "grant_id": "c7836eff-7451-4b67-8bef-633e3a7d647b",
  "iat": 1678942218,
  "iss": "https://harbinger.verify.ibm.com/oauth2",
  "nbf": 1678942218,
  "preferred_username": "[email protected]",
  "scope": "openid payment",
  "sub": "671000CCGT",
  "token_type": "DPoP",
  "token_use": "access_token"
}

Maintenant que le jeton a été émis, il peut être utilisé pour accéder à une ressource protégée.

Utilisation du jeton DPoP-bound

Lorsque le client accède à une ressource protégée API autorisée à l'aide du jeton DPoP, il génère une nouvelle preuve DPoP signée par la même clé privée. Contrairement aux jetons Bearer, l'en-tête "Authorization" doit commencer par DPoP (à la place de "Bearer"). Cela indique l'utilisation d'un jeton DPoP-bound et nécessite que la preuve soit incluse dans l'en-tête "dpop". La preuve DPoP doit contenir les revendications JWT standard, telles que "iat", "jti" et "exp". En outre, les éléments suivants doivent être ajoutés :

RéclamationDescriptionExemple
htmMéthode HTTPGET
htuHTTP URLhttps://jke.com/photos
athCalculé comme le hachage SHA-256 BASE64URL-encoded de la valeur du jeton d'accèsYSm0UcYpuIR6HZfVU9dnIg

L'API (ou la passerelle) analyse le jeton (s'il ne s'agit pas d'un JWT) et effectue les opérations suivantes :

  1. Valider la signature de la preuve DPoP.
// Importing node-jose module
const jose  = require('node-jose');

// DPoP proof, usually extracted from the request object
const dpopProof = '...';

// Validate the JWT
let dpopProofUnpacked = await jose.JWS.createVerify().
  verify(dpopProof, { allowEmbeddedKey: true });
  1. Comparer le hachage du jeton d'accès pour vérifier que la preuve DPoP utilisée est associée au jeton.
// Importing crypto module
const { createHash } = require('crypto');

// Access token, usually extracted from the Authorization header
const token = '...';

// Compute the expected access token hash (ath) claim in the proof
let digest = createHash('sha256').update(token).digest();
let atHash = encode(digest.slice(0, digest.length / 2));

// Compare the atHash with the 'ath' claim in the DPoP proof
  1. Générer l'empreinte codée du pouce à partir du JWK intégré.
// Compute the thumbprint hash
let thumbprint = await dpopProofUnpacked.key.thumbprint('SHA-256');
let computedFingerprint = jose.util.base64url.encode(thumbprint);
  1. Valider que les revendications "htm" et "htu" correspondent à la méthode HTTP et à l' URL HTTP de l'extrémité de la ressource.

  2. Introspecter le jeton ou valider le JWT (s'il est formaté de cette manière).

  3. Extraire la valeur cnf.jkt et la comparer au hachage de l'empreinte calculé à l'étape 3. S'ils correspondent, d'autres décisions d'autorisation sont prises, comme la comparaison des champs d'application accordés, etc.

Conclusion

Les jetons DPoP-bound ajoutent une forte couche d'assurance en exigeant une preuve de possession par l'utilisation de la preuve DPoP signée. Ils limitent l'utilisation abusive des jetons par des parties non autorisées. Les parties non autorisées comprennent les acteurs malveillants, les API de ressources ayant accès au jeton et qui le réutilisent pour accéder à d'autres points d'extrémité, etc. Contrairement aux jetons d'accès liés à un certificat, qui nécessitent le protocole TLS mutuel, la preuve DPoP est générée au niveau de l'application et convient aux clients qui ne peuvent pas recevoir de certificats. Par exemple, les applications à page unique écrites à l'aide de React ou Angular.js qui n'ont pas de backend.

Les applications clients définies sur IBM Security Verify via OAuth 2.0 Dynamic Client Registration ou la console d'administration peuvent être configurées pour exiger des preuves DPoP afin d'émettre des jetons d'accès liés à la clé de signature. Pour plus de détails, voir le connecteur d'application OpenID Connect.

💎

Vivek Shankar, IBM Security