web-dev-qa-db-fra.com

Comment signer un JWT avec une clé privée (pem) dans CryptoJS?

J'essaie de créer un JWT signé dans Postman avec le code suivant

function base64url(source) {
    // Encode in classical base64
    encodedSource = CryptoJS.enc.Base64.stringify(source);

    // Remove padding equal characters
    encodedSource = encodedSource.replace(/=+$/, '');

    // Replace characters according to base64url specifications
    encodedSource = encodedSource.replace(/\+/g, '-');
    encodedSource = encodedSource.replace(/\//g, '_');

    return encodedSource;
}

function addIAT(request) {
    var iat = Math.floor(Date.now() / 1000) + 257;
    data.iat = iat;
    return data;
}


var header = {
    "typ": "JWT",
    "alg": "HS256"
};

var data = {
    "fname": "name",
    "lname": "name",
    "email": "[email protected]",
    "password": "abc123$"
};

data = addIAT(data);

var secret = 'myjwtsecret';

// encode header
var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
var encodedHeader = base64url(stringifiedHeader);

// encode data
var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data));
var encodedData = base64url(stringifiedData);

// build token
var token = encodedHeader + "." + encodedData;

// sign token
var signature = CryptoJS.HmacSHA256(token, secret);
signature = base64url(signature);
var signedToken = token + "." + signature;

postman.setEnvironmentVariable("payload", signedToken);

Code tiré de https://Gist.github.com/corbanb/db03150abbe899285d6a86cc480f674d .

J'ai essayé de saisir le PEM comme secret, mais cela ne fonctionne pas. Je ne trouve pas non plus de surcharge HmacSHA256 qui prend un PEM.

Comment cela peut-il être fait?

9
Aleksandar

La mention de facteur a changé cela. J'ai une solution pour vous, mais ce n'est pas du tout une façon propre.

Vous devrez créer une demande que vous devrez exécuter chaque fois que vous ouvrirez Postman. Allez comme suit:

Side-loading jsrsasign-js

Le but de cette requête est de charger latéralement jsrsasign-js Et de le stocker dans une variable globale Postman.

Une fois cela fait, vous pouvez ensuite utiliser ce contenu ailleurs. Pour chaque demande dont vous avez besoin d'une signature JSA RSA256, le script de pré-demande suivant mettra à jour une variable (ici, token) avec le jeton:

var navigator = {};
var window = {};
eval(pm.globals.get("jsrsasign-js"));

function addIAT(request) {
    var iat = Math.floor(Date.now() / 1000) + 257;
    data.iat = iat;
    return data;
}

var header = {"alg" : "RS256","typ" : "JWT"};
var data = {
    "fname": "name",
    "lname": "name",
    "email": "[email protected]",
    "password": "abc123$"
};

data = addIAT(data);

var privateKey = "-----BEGIN RSA PRIVATE KEY----- \
MIIBOQIBAAJAcrqH0L91/j8sglOeroGyuKr1ABvTkZj0ATLBcvsA91/C7fipAsOn\
RqRPZr4Ja+MCx0Qvdc6JKXa5tSb51bNwxwIDAQABAkBPzI5LE+DuRuKeg6sLlgrJ\
h5+Bw9kUnF6btsH3R78UUANOk0gGlu9yUkYKUkT0SC9c6HDEKpSqILAUsXdx6SOB\
AiEA1FbR++FJ56CEw1BiP7l1drM9Mr1UVvUp8W71IsoZb1MCIQCKUafDLg+vPj1s\
HiEdrPZ3pvzvteXLSuniH15AKHEuPQIhAIsgB519UysMpXBDbtxJ64jGj8Z6/pOr\
NrwV80/EEz45AiBlgTLZ2w2LjuNIWnv26R0eBZ+M0jHGlD06wcZK0uLsCQIgT1kC\
uNcDTERjwEbFKJpXC8zTLSPcaEOlbiriIKMnpNw=\
-----END RSA PRIVATE KEY-----";

var sHeader = JSON.stringify(header);
var sPayload = JSON.stringify(data);

var sJWT = KJUR.jws.JWS.sign(header.alg, sHeader, sPayload, privateKey);

pm.variables.set('token', sJWT);

Dans l'ordre: - Je définis les objets fictifs window et navigator comme jsrsasign-js En a besoin. - J'ai ensuite eval() le contenu de ce que nous avons récupéré plus tôt afin de tout réhydrater - Le reste de votre code est une simple utilisation de jsrsasign-js. Vos informations de jeton sont là et j'y ai défini une clé privée. Vous pouvez changer cela ou utiliser une variable d'environnement; il est juste là à des fins de démonstration. J'utilise ensuite simplement la bibliothèque réhydratée pour la signer et je mets la variable à la valeur du JWT signé.


Un PEM, comme vous vous y référez, est un format de conteneur spécifiant une combinaison de clé publique et/ou privée. Vous l'utilisez pour signer en utilisant HMAC-SHA256, Qui fonctionne sur un secret partagé . Cela ne fonctionnera évidemment pas (sauf si vous adoptez l'approche du pauvre et utilisez votre clé publique comme secret partagé).

Heureusement, il existe d'autres méthodes de signature définies dans les RFC. Par exemple, il existe un moyen de signer en utilisant RSA, et un moyen très pratique de définir une clé publique comme clé Web JSON (JWK). Nous allons tirer parti des deux.

J'ai généré une paire de clés pour les tests, elles sont nommées out et out.pub. L'outil de génération est genrsa (et en tant que tel, il s'agit d'une paire de clés RSA).

Pour signer, nous allons devoir changer quelques petites choses:

  • Nous modifions les algorithmes de HS256 À RS256, Comme expliqué ci-dessus
  • Nous allons avoir besoin d'une nouvelle bibliothèque pour faire la signature elle-même, car crypto-js Ne prend pas en charge la cryptographie à clé asymétrique. Nous reviendrons sur le module natif crypto, bien qu'il existe des alternatives pure-JS

Le code:

var CryptoJS = require("crypto-js");
var keyFileContent = require("fs").readFileSync("./out");
var pubkey = require("fs").readFileSync("./out.pub");
var base64url = require("base64url");
var nJwt = require("njwt");
function addIAT(request) {
    var iat = Math.floor(Date.now() / 1000) + 257;
    data.iat = iat;
    return data;
}


var header = {
    "typ": "JWT",
    "alg": "RS256"
};

var data = {
    "fname": "name",
    "lname": "name",
    "email": "[email protected]",
    "password": "abc123$"
};

data = addIAT(data);

// encode header
var stringifiedHeader = JSON.stringify(header);
var encodedHeader = base64url(stringifiedHeader);

// encode data
var stringifiedData = JSON.stringify(data);
var encodedData = base64url(stringifiedData);

// build token
var token = encodedHeader + "." + encodedData;

// sign token
var signatureAlg = require("crypto").createSign("sha256");
signatureAlg.update(token);
var signature = signatureAlg.sign(keyFileContent);
signature = base64url(signature);
var signedToken = token + "." + signature;

console.log(signedToken);

// Verify
var verifier = new nJwt.Verifier();
verifier.setSigningAlgorithm('RS256');
verifier.setSigningKey(pubkey);
verifier.verify(signedToken, function() {
  console.log(arguments);
});

Et c'est tout! C'est littéralement aussi simple que cela, même si je ne recommanderais pas de réécrire la fonction sign() à partir de crypto à partir de zéro. Laissez-le à une bibliothèque qui a fait l'objet d'une inspection approfondie par la communauté, et la cryptographie est une affaire assez sérieuse.

4
Sébastien Renauld