Как подписать JWT с помощью закрытого ключа (pem) в CryptoJS? - PullRequest
0 голосов
/ 29 декабря 2018

Я пытаюсь создать подписанный JWT в почтальоне со следующим кодом

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@domain.com",
    "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);

Код взят из https://gist.github.com/corbanb/db03150abbe899285d6a86cc480f674d.

Я пытался ввестиPEM как секрет, но не работает.Также не удается найти какую-либо перегрузку HmacSHA256, которая принимает PEM.

Как это можно сделать?

1 Ответ

0 голосов
/ 29 декабря 2018

Упоминание о почтальоне изменило это.У меня есть решение для вас, но это не совсем чистый способ.

Вам нужно будет создать запрос, который вам нужно будет выполнять каждый раз, когда вы открываете почтальон.Выполните следующее:

Side-loading jsrsasign-js

Цель этого запроса - загрузить jsrsasign-js и сохранить его в глобальной переменной Postman.

Как только это будет сделано, вы сможете использовать этот контент в другом месте.Для каждого запроса вам нужна подпись RSA256 JWT, следующий скрипт предварительного запроса будет обновлять переменную (здесь token) с токеном:

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@domain.com",
    "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);

Для того, чтобы: - я определяю mock windowи navigator объекты, поскольку jsrsasign-js нуждаются в них.- Затем я eval() содержимое того, что мы извлекли ранее, чтобы все регидратировать - Остальная часть вашего кода простое использование jsrsasign-js.Ваша информация о токене есть, и я определил закрытый ключ там.Вы можете изменить это или использовать переменную окружения;это просто для демонстрационных целей.Затем я просто использую регидратированную библиотеку, чтобы подписать ее, и установите для переменной значение подписанного JWT.


A PEM, как вы на него ссылаетесь, - это формат контейнера, определяющий комбинациюоткрытого и / или закрытого ключа.Вы используете его для подписи, используя HMAC-SHA256, который работает с shared secret.Очевидно, что это не сработает (если вы не примете подход бедняка и не используете свой открытый ключ в качестве общего секрета).

К счастью, в RFC есть и другие методы подписи.Например, есть способ подписи с использованием RSA и очень удобный способ определения открытого ключа как веб-ключа JSON (JWK).Мы собираемся использовать оба.

Я сгенерировал пару ключей для тестирования, они названы out и out.pub.Инструмент генерации - genrsa (и поэтому он является парой ключей RSA).

Чтобы подписать, нам нужно изменить несколько вещей:

  • Мы меняем алгоритмы с HS256 на RS256, как объяснено выше
  • Нам понадобится новая библиотека для самой подписи, поскольку crypto-js не поддерживает шифрование асимметричного ключа.Мы вернемся к собственному модулю crypto, хотя есть альтернативы чисто JS

Код:

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@domain.com",
    "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);
});

И это все!Это буквально так просто, хотя я бы не рекомендовал переписывать функцию sign() с crypto с нуля.Оставьте это библиотеке, которая была тщательно проверена сообществом, и криптография - довольно серьезное дело.

...