Node.js: особенности и ограничения node:crypto

Модуль node:crypto является фундаментальным компонентом криптографической инфраструктуры Node.js. Он предоставляет низкоуровневый доступ к OpenSSL и используется как основа для большинства криптографических операций в экосистеме JavaScript, включая подпись токенов, шифрование данных и проверку целостности.

Несмотря на то, что высокоуровневые библиотеки вроде jose абстрагируют сложность криптографии, понимание ограничений и особенностей node:crypto критично для корректной и безопасной работы с JWT, JWS, JWE и JWK.


Базовая модель node:crypto

Модуль предоставляет функциональность через обёртку над OpenSSL, что означает зависимость от:

  • версии OpenSSL, встроенной в Node.js
  • конфигурации сборки Node.js
  • политики безопасности (FIPS mode, если включён)

Основные категории возможностей:

Хеширование

  • SHA-1 (устаревший)
  • SHA-256 / SHA-512
  • MD5 (небезопасен, но доступен)

HMAC

  • HMAC-SHA256 и другие вариации

Шифрование

  • AES (CBC, GCM, CTR)
  • RSA (PKCS#1 v1.5, OAEP)
  • ECDSA / ECDH

Генерация ключей

  • симметричные ключи
  • асимметричные пары

Ключевая проблема: абстракция OpenSSL

Node.js не реализует криптографию самостоятельно. Это приводит к нескольким важным ограничениям:

Зависимость от версии OpenSSL

Разные версии Node.js используют разные версии OpenSSL, что влияет на:

  • доступность алгоритмов
  • поведение padding-режимов
  • поддержку новых стандартов (например, Ed25519)

Некоторые алгоритмы могут:

  • быть отключены по умолчанию
  • требовать legacy provider
  • полностью отсутствовать в старых версиях Node.js

Непредсказуемость алгоритмов

Один и тот же код может вести себя по-разному:

  • в Node.js 16 (OpenSSL 1.1.1)
  • в Node.js 20+ (OpenSSL 3.x)

Особенно это критично для:

  • RSA-PSS
  • EdDSA
  • ECDSA с нестандартными кривыми

Ограничения безопасности node:crypto

1. Устаревшие алгоритмы доступны по умолчанию

Node.js исторически поддерживает алгоритмы, которые считаются небезопасными:

  • MD5
  • SHA-1 (для подписи)
  • RSA с PKCS#1 v1.5 padding

Это создаёт риск:

  • случайного использования слабых схем
  • совместимости в ущерб безопасности

2. Отсутствие строгой политики безопасных дефолтов

node:crypto не запрещает небезопасные операции. Например:

createSign('RSA-SHA1')

возможно, хотя SHA-1 давно считается компрометированным.


3. Ошибки использования ключей

Типичные проблемы:

  • использование симметричного ключа там, где нужен асимметричный
  • неправильная длина ключа AES
  • повторное использование IV в GCM

Node.js не валидирует криптографическую корректность на уровне архитектуры.


Особенности работы с асимметричной криптографией

RSA

Поддерживаются:

  • PKCS#1 v1.5 (устаревший)
  • OAEP (рекомендуемый)

Проблемы:

  • несовместимость padding между библиотеками
  • различия в реализации OpenSSL

ECDSA

Используется для цифровых подписей, но имеет особенности:

  • требовательность к кривым (P-256, P-384, P-521)
  • чувствительность к формату DER/JOSE

Ed25519

Поддержка появилась относительно недавно и зависит от версии Node.js.

Ограничения:

  • не везде доступен в legacy режимах
  • несовместимость с некоторыми реализациями OpenSSL

Симметричное шифрование

AES-GCM как стандарт

Рекомендуемый режим:

  • обеспечивает конфиденциальность и целостность
  • требует уникального IV

Критические ошибки:

  • повторное использование nonce полностью ломает безопасность
  • неправильная обработка auth tag

CBC и его риски

AES-CBC:

  • требует отдельного HMAC для целостности
  • уязвим к padding oracle атакам при неправильной реализации

Взаимодействие с библиотекой jose

Библиотека jose строится поверх криптографических возможностей Node.js, но не зависит от crypto напрямую в логике протоколов — она использует его как backend.

Основные задачи node:crypto в jose:

  • генерация подписей (JWS)
  • шифрование (JWE)
  • работа с ключами (JWK import/export)
  • проверка JWT

Ограничения при использовании jose через node:crypto

1. Несовпадение алгоритмов

Некоторые алгоритмы JOSE:

  • ES256
  • RS256
  • EdDSA

могут работать по-разному в зависимости от OpenSSL.


2. Проблемы с импортом ключей

Форматы:

  • PEM
  • JWK
  • DER

Node.js требует точного соответствия формата, иначе:

  • ошибки парсинга
  • некорректные подписи

3. Различие между WebCrypto и node:crypto

В современных версиях Node.js есть WebCrypto API, и он отличается:

node:crypto WebCrypto
синхронный API асинхронный
OpenSSL backend браузерный стандарт
больше алгоритмов более строгая спецификация

jose может переключаться между ними, что влияет на поведение.


Производительность и системные ограничения

Синхронность операций

node:crypto в основном синхронный:

  • блокирует event loop при тяжёлых операциях
  • может снижать throughput сервера

Особенно заметно при:

  • массовой генерации JWT
  • RSA-операциях

Ограничения OpenSSL

  • размер ключей RSA влияет на скорость экспоненциально
  • ECDSA быстрее, но чувствителен к параметрам кривой

Безопасные практики работы

Использование современных алгоритмов

Рекомендуемые:

  • ES256 / ES384 / ES512
  • RS256 (с OAEP для шифрования)
  • EdDSA (Ed25519)

Запрет устаревших схем

Следует избегать:

  • SHA-1
  • MD5
  • RSA-PKCS1 v1.5 для новых систем

Контроль ключей

Критично:

  • хранить ключи вне кода
  • использовать HSM или KMS при возможности
  • ограничивать доступ к приватным ключам

Типичные ошибки разработчиков

1. Неправильный выбор алгоритма

Часто выбирается:

  • RS256 «по привычке»
  • вместо более современных схем

2. Игнорирование nonce/IV

Особенно в AES-GCM:

  • повтор IV = компрометация данных

3. Смешивание библиотек

Использование:

  • crypto + сторонние реализации JOSE

приводит к:

  • несовместимым токенам
  • ошибкам подписи

Влияние версии Node.js

Поведение криптографии меняется между версиями:

  • Node.js 14: старый OpenSSL, больше legacy алгоритмов
  • Node.js 18: переходный режим
  • Node.js 20+: OpenSSL 3, строгие ограничения

Это влияет на:

  • доступность алгоритмов
  • дефолтные политики безопасности
  • совместимость JWT

Итоговая картина ограничений

node:crypto можно рассматривать как мощный, но низкоуровневый инструмент, в котором:

  • безопасность зависит от разработчика
  • совместимость зависит от OpenSSL
  • поведение зависит от версии Node.js

Библиотеки вроде jose закрывают часть этих проблем, но не устраняют фундаментальные ограничения криптографической платформы Node.js.