При аудите кода, использующего TweetNaCl.js / nacl.js, первоочередное
внимание уделяется тому, как именно применяются криптографические
примитивы. Библиотека предоставляет низкоуровневые операции, и любая
ошибка на уровне вызова приводит к полной компрометации
безопасности.
Ключевые моменты:
- Использование только проверенных функций:
nacl.box,
nacl.secretbox, nacl.sign,
nacl.hash
- Отсутствие самодельных криптографических алгоритмов поверх
примитивов
- Проверка корректности схемы: шифрование + аутентификация должны
применяться совместно
- Недопустимость частичного использования (например, шифрование без
проверки целостности)
Особенно критично исключить ситуации, где разработчик использует
только nacl.secretbox для хранения данных, но не проверяет
nonce или повторно его использует.
Проверка управления ключами
Безопасность всей схемы в TweetNaCl.js полностью зависит от
управления ключами. При аудите необходимо выявить следующие
проблемы:
- Генерация ключей должна происходить через
nacl.randomBytes
- Недопустимо использование предсказуемых значений (timestamp, UUID,
короткие строки)
- Ключи не должны храниться в коде, localStorage без шифрования или
query-параметрах URL
- Отсутствие логирования секретных ключей в консоль или telemetry
Особое внимание уделяется месту хранения приватных ключей при
использовании nacl.box.keyPair() и
nacl.sign.keyPair().
Проверка работы с nonce
Nonce в NaCl — критически важный элемент. Ошибки в его использовании
часто приводят к полному взлому шифрования.
Типичные проблемы:
- Повторное использование nonce с одним и тем же ключом
- Генерация nonce через
Math.random()
- Статические nonce (например, заполненные нулями массивы)
- Отсутствие хранения nonce вместе с ciphertext
Корректная практика:
nacl.randomBytes(nacl.secretbox.nonceLength)
- Уникальность nonce для каждого сообщения гарантируется на уровне
архитектуры
- Хранение nonce в явном виде рядом с зашифрованными данными
Проверка корректности
схемы шифрования
TweetNaCl.js предоставляет строительные блоки, но не навязывает
архитектуру. Поэтому важно проверить, как именно собрана схема:
- Используется ли authenticated encryption (например,
nacl.secretbox)
- Не реализовано ли ручное объединение
nacl.box +
отдельная MAC-функция без необходимости
- Нет ли двойного шифрования без обоснования
- Проверка порядка операций: сначала шифрование, затем подпись (или
наоборот — в зависимости от протокола)
Особое внимание уделяется отсутствию «самодельных протоколов», где
разработчик комбинирует примитивы без криптографического
обоснования.
Проверка обработки ошибок
Ошибки дешифрования и проверки подписи должны обрабатываться строго и
предсказуемо.
Аудит включает:
- Проверка возврата
null при неуспешной валидации
nacl.sign.open
- Отсутствие утечек причин ошибки (например, различие между “неверный
ключ” и “повреждённые данные”)
- Единообразная обработка исключений в криптографическом слое
- Недопустимость fallback-логики при ошибке проверки подписи
Любая информация, раскрывающая причину криптографической ошибки,
потенциально может быть использована для атак по побочным каналам.
Проверка генерации случайных
чисел
TweetNaCl.js использует криптографически стойкий генератор, но аудит
должен подтвердить, что:
- Не используется
Math.random() ни в одном
криптографическом контексте
- Все ключи, nonce и соли генерируются через
nacl.randomBytes
- Нет внешних polyfill-реализаций RNG, снижающих энтропию
- В Node.js и браузере поведение генератора не переопределяется
Особенно опасны ситуации, когда библиотечные функции используются
корректно, но вспомогательные данные (например, salt для KDF)
генерируются неправильно.
Проверка схем подписи
При использовании nacl.sign важно анализировать:
- Подписываются ли действительно все критические поля сообщения
- Нет ли частичной подписи (например, только payload без
метаданных)
- Корректность разделения
sign и
sign.open
- Отсутствие самостоятельных реализаций проверки подписи
Частая ошибка — использование подписей только для части структуры
данных, что позволяет подменять незащищённые поля.
Проверка сериализации данных
Криптографические ошибки часто возникают не в алгоритмах, а в
сериализации:
- Проверка стабильности формата (JSON может менять порядок
ключей)
- Использование бинарных форматов (Uint8Array) без потерь при
преобразованиях
- Недопустимость повторного кодирования (base64 → utf8 → base64)
- Проверка единообразия encoding/decoding на всех слоях
Особое внимание уделяется ситуациям, когда подпись считается от
одного представления данных, а проверяется на другом.
Проверка работы с памятью
и утечками
В JavaScript отсутствует ручное управление памятью, но
криптографический код требует дополнительного контроля:
- Обнуление буферов с ключами после использования (если реализовано
вручную)
- Отсутствие долгоживущих ссылок на секретные данные
- Проверка кэширования криптографических объектов
- Недопустимость хранения ключей в глобальных singleton-объектах
Хотя NaCl не предоставляет встроенных средств очистки памяти,
архитектурно важно минимизировать время жизни секретов.
Проверка
совместимости и версий библиотеки
TweetNaCl.js и nacl.js имеют различия в реализации и поддержке
функций:
- Проверка, что используется одна конкретная реализация, без
смешивания API
- Фиксация версии зависимости (lockfile)
- Проверка отсутствия форков с изменённой криптографией
- Контроль обновлений и миграций API
Несовместимость версий может приводить к тому, что данные,
зашифрованные одной версией, некорректно расшифровываются другой.
Проверка архитектуры
протокола поверх NaCl
Самая частая причина уязвимостей — не библиотека, а протокол вокруг
неё.
Аудит включает:
- Наличие чёткой схемы обмена ключами (например, X25519 через
nacl.box)
- Проверка отсутствия самодельных протоколов аутентификации
- Разделение ролей: шифрование, подпись, транспорт
- Отсутствие смешивания ключей разных контекстов
Особенно важно убедиться, что ключи не используются повторно для
разных целей (например, один ключ и для подписи, и для шифрования).
Проверка
устойчивости к типичным криптоошибкам
В ходе аудита проверяются известные классы уязвимостей:
- повторное использование nonce
- утечка ключей через логи
- отсутствие проверки подписи
- неправильная сериализация
- использование небезопасного RNG
- смешивание протоколов шифрования и подписи
Каждый из этих пунктов должен быть либо исключён архитектурно, либо
явно обоснован и изолирован.