Шифрование данных в REST API

REST API без криптографической защиты передаёт данные в открытом виде, что делает их уязвимыми к перехвату, подмене и повторному воспроизведению. В экосистеме JavaScript одной из наиболее компактных и надёжных реализаций криптографических примитивов является TweetNaCl.js — порт NaCl (Networking and Cryptography library), предоставляющий минималистичный, но безопасный набор операций.

TweetNaCl.js ориентирован на использование проверенных конструкций: публично-ключевое шифрование, симметричное шифрование, цифровые подписи. В контексте REST API чаще всего применяются два подхода: шифрование сообщений между клиентом и сервером и защита чувствительных payload’ов поверх уже существующего HTTPS-канала.


Библиотека предоставляет три ключевых механизма:

  • nacl.box — асимметричное шифрование с использованием пары ключей
  • nacl.secretbox — симметричное шифрование с общим ключом
  • nacl.sign — цифровые подписи для проверки подлинности данных

Для REST API наиболее практичны box и secretbox.


Симметричное шифрование данных через secretbox

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

Ключевые свойства:

  • один ключ для шифрования и дешифрования
  • высокая скорость
  • обязательное использование nonce
import nacl from "tweetnacl";
import util from "tweetnacl-util";

// Генерация ключа
const key = nacl.randomBytes(32);

// Сообщение
const message = "Секретные данные запроса";
const nonce = nacl.randomBytes(24);

// Кодирование
const messageUint8 = util.decodeUTF8(message);

// Шифрование
const encrypted = nacl.secretbox(messageUint8, nonce, key);

// Декодирование на стороне сервера
const decrypted = nacl.secretbox.open(encrypted, nonce, key);

const result = util.encodeUTF8(decrypted);

Особенности nonce

Nonce (number used once) должен быть уникальным для каждого сообщения при одном ключе. Повтор nonce полностью компрометирует безопасность шифрования.


Асимметричное шифрование через nacl.box

box применяется для безопасного обмена сообщениями без предварительно общего секрета. Это типичный сценарий REST API с авторизацией через ключи клиента.

Используются:

  • публичный ключ сервера
  • приватный ключ клиента
  • nonce для каждого сообщения
import nacl from "tweetnacl";
import util from "tweetnacl-util";

// Генерация ключей клиента
const clientKeyPair = nacl.box.keyPair();

// Публичный ключ сервера (получен заранее)
const serverPublicKey = new Uint8Array([...]);

const nonce = nacl.randomBytes(24);

const message = util.decodeUTF8("Запрос к API");

// Шифрование
const encrypted = nacl.box(
  message,
  nonce,
  serverPublicKey,
  clientKeyPair.secretKey
);

// Дешифрование на сервере
const decrypted = nacl.box.open(
  encrypted,
  nonce,
  clientKeyPair.publicKey,
  serverSecretKey
);

const decoded = util.encodeUTF8(decrypted);

Модель интеграции в REST API

Шифрование в REST API обычно применяется не вместо HTTPS, а поверх него. Это создаёт дополнительный уровень защиты:

  • HTTPS защищает транспорт
  • NaCl защищает payload и бизнес-данные

Типичный поток:

  1. Клиент генерирует ключевую пару
  2. Публичный ключ отправляется серверу
  3. Сервер сохраняет ключ клиента
  4. Каждое сообщение шифруется через box
  5. Сервер расшифровывает и обрабатывает данные

Структура зашифрованного запроса

Обычно REST payload дополняется метаданными:

{
  "nonce": "base64...",
  "payload": "base64...",
  "clientPublicKey": "base64..."
}

На стороне сервера происходит:

  • декодирование base64
  • проверка nonce
  • расшифровка сообщения
  • валидация структуры данных

Кодирование данных (base64)

TweetNaCl работает с Uint8Array, поэтому REST API требует кодирования:

const encoded = util.encodeBase64(encrypted);
const decoded = util.decodeBase64(encoded);

Без этого невозможна передача через JSON.


Защита от replay-атак

Replay-атаки возникают при повторной отправке ранее перехваченного запроса. Защита строится на:

  • уникальном nonce
  • временных метках
  • хранении использованных nonce на сервере

Пример проверки:

if (usedNonces.has(nonce)) {
  throw new Error("Replay attack detected");
}
usedNonces.add(nonce);

Использование в авторизации REST API

TweetNaCl.js может применяться для создания криптографической авторизации без паролей.

Схема:

  • клиент подписывает запрос
  • сервер проверяет подпись через публичный ключ

Пример:

const signature = nacl.sign.detached(
  message,
  clientSecretKey
);

const isValid = nacl.sign.detached.verify(
  message,
  signature,
  clientPublicKey
);

Это позволяет отказаться от классических session tokens в некоторых архитектурах.


Ошибки при интеграции

На практике встречаются критические ошибки:

  • повторное использование nonce
  • хранение ключей в localStorage без защиты
  • шифрование без проверки целостности payload
  • смешивание кодировок UTF-8 и Uint8Array
  • попытка использовать NaCl вместо HTTPS

Архитектурные ограничения

TweetNaCl.js оптимизирован под безопасность, а не под гибкость:

  • фиксированные размеры ключей и nonce
  • отсутствие встроенных режимов шифрования
  • невозможность частичной модификации алгоритмов
  • строгая модель работы с бинарными данными

Эти ограничения являются частью дизайна и уменьшают поверхность атак.


Практическая схема REST API с TweetNaCl.js

Типичная безопасная конфигурация выглядит так:

  • HTTPS как транспорт
  • nacl.box для обмена сообщениями
  • nonce на каждый запрос
  • публичные ключи в профиле пользователя
  • приватные ключи только на сервере/клиенте

Структура запроса:

POST /api/data

{
  "nonce": "...",
  "data": "...",
  "clientId": "123"
}

Обработка:

  1. извлечение clientId
  2. получение публичного ключа
  3. расшифровка payload
  4. проверка nonce
  5. выполнение бизнес-логики

Производительность и применение

TweetNaCl.js написан на JavaScript без нативных зависимостей, что делает его:

  • удобным для браузера
  • предсказуемым в поведении
  • достаточно быстрым для API-уровня нагрузки

Однако при высоконагруженных системах предпочтительнее серверные реализации NaCl или libsodium с нативными биндингами.


Безопасная модель хранения ключей

Правильная стратегия хранения:

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

Использование TweetNaCl.js в REST API создаёт криптографически строгую модель взаимодействия, в которой каждое сообщение становится независимым защищённым объектом с гарантированной целостностью и конфиденциальностью.