В браузерных и Node.js-приложениях библиотека Jsrsasign используется для реализации криптографических операций без необходимости подключения нативных модулей. Она поддерживает RSA, ECDSA, HMAC, SHA-хеширование, а также работу с X.509 сертификатами и форматом JWS/JWT.
Подключение в браузере:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/10.8.6/jsrsasign-all-min.js"></script>
В Node.js:
const jsrsasign = require("jsrsasign");
const { KEYUTIL, KJUR } = jsrsasign;
Ключевая идея при защите данных перед отправкой — не ограничиваться шифрованием текста, а использовать комбинацию асимметричного и симметричного шифрования.
RSA используется для обмена ключами и шифрования небольших объёмов данных.
Создание ключевой пары:
const rsaKeypair = KEYUTIL.generateKeypair("RSA", 2048);
const privateKey = rsaKeypair.prvKeyObj;
const publicKey = rsaKeypair.pubKeyObj;
Экспорт ключей в PEM-формат:
const privatePEM = KEYUTIL.getPEM(privateKey, "PKCS8PRV");
const publicPEM = KEYUTIL.getPEM(publicKey);
Загрузка ключа из PEM:
const pubKey = KEYUTIL.getKey(publicPEM);
const prvKey = KEYUTIL.getKey(privatePEM);
Важно учитывать, что RSA не предназначен для шифрования больших сообщений. Максимальный размер зависит от длины ключа и padding-схемы.
Базовое шифрование небольшого сообщения:
const pubKey = KEYUTIL.getKey(publicPEM);
const encrypted = pubKey.encrypt("секретное сообщение");
const encryptedBase64 = hextob64(encrypted);
Расшифрование:
const prvKey = KEYUTIL.getKey(privatePEM);
const decryptedHex = prvKey.decrypt(b64tohex(encryptedBase64));
console.log(decryptedHex);
Такой подход применяется редко в чистом виде из-за ограничений RSA и высокой вычислительной стоимости.
Реальные системы используют комбинацию:
const aesKey = KJUR.crypto.Util.getRandomHexOfNbytes(16); // 128-bit key
const plainText = "Конфиденциальные данные пользователя";
const cipher = new KJUR.crypto.Cipher({
alg: "aes128",
pass: aesKey
});
const encryptedData = cipher.encrypt(plainText);
const pubKey = KEYUTIL.getKey(publicPEM);
const encryptedAesKey = pubKey.encrypt(aesKey);
const encryptedAesKeyB64 = hextob64(encryptedAesKey);
Теперь передаётся два объекта:
encryptedData — зашифрованные данныеencryptedAesKeyB64 — зашифрованный ключconst prvKey = KEYUTIL.getKey(privatePEM);
const aesKeyHex = prvKey.decrypt(b64tohex(encryptedAesKeyB64));
const cipher = new KJUR.crypto.Cipher({
alg: "aes128",
pass: aesKeyHex
});
const decrypted = cipher.decrypt(encryptedData);
Типичная структура отправляемого объекта:
const payload = {
key: encryptedAesKeyB64,
data: encryptedData,
algorithm: "RSA + AES-128"
};
Такой формат позволяет серверу:
Шифрование скрывает данные, но не подтверждает их подлинность. Для этого используется подпись.
const sig = new KJUR.crypto.Signature({
alg: "SHA256withRSA",
});
sig.init(privatePEM);
sig.updateString(JSON.stringify(payload));
const signature = sig.sign();
const signatureB64 = hextob64(signature);
const verifier = new KJUR.crypto.Signature({
alg: "SHA256withRSA",
});
verifier.init(publicPEM);
verifier.updateString(JSON.stringify(payload));
const isValid = verifier.verify(b64tohex(signatureB64));
Проверка подписи должна выполняться до расшифровки данных, чтобы исключить подмену содержимого.
Jsrsasign поддерживает работу с JSON Web Token:
const header = { alg: "RS256", typ: "JWT" };
const payload = { userId: 123, role: "admin" };
const jwt = KJUR.jws.JWS.sign(
"RS256",
JSON.stringify(header),
JSON.stringify(payload),
privatePEM
);
const isValid = KJUR.jws.JWS.verify(jwt, publicPEM, ["RS256"]);
JWT часто заменяет ручную реализацию шифрования в прикладных системах авторизации.
В реальных API-проектах схема выглядит следующим образом:
Пример итогового запроса:
fetch("/api/secure", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
key: encryptedAesKeyB64,
data: encryptedData,
signature: signatureB64
})
});
RSA подходит только для ключей и коротких строк.
Шифрование не гарантирует целостность данных.
Один ключ на множество запросов снижает безопасность.
Hex/Base64 преобразования должны быть строго согласованы между клиентом и сервером.
Структурно система выглядит так:
Клиент:
Сервер:
Такая модель обеспечивает разделение ответственности между алгоритмами и устойчивость к компрометации отдельных компонентов.