Хранение токенов и чувствительных данных: что допустимо

Idb-keyval — это лёгкая обёртка над IndexedDB, предоставляющая простой API для асинхронного хранения данных в браузере. Она позволяет хранить ключ-значение без необходимости самостоятельно управлять транзакциями и открытием базы данных. Основные функции включают:

  • get(key) — извлечение значения по ключу.
  • set(key, value) — сохранение значения по ключу.
  • del(key) — удаление записи.
  • clear() — очистка всех данных.
  • keys() — получение массива всех ключей.

Idb-keyval работает с любыми сериализуемыми объектами, включая строки, числа, массивы и JSON-объекты, что делает её удобной для хранения токенов, настроек и других небольших данных.

Создание и настройка хранилища

Idb-keyval позволяет создавать отдельные хранилища, что полезно для логической изоляции данных. Для этого используется объект Store:

import { Store, get, set } from 'idb-keyval';

const myStore = new Store('my-database', 'tokens');

await set('accessToken', '123456', myStore);
const token = await get('accessToken', myStore);

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

Хранение токенов

Токены аутентификации (access token, refresh token) часто требуют безопасного хранения на клиенте. Idb-keyval хранит данные на стороне браузера, но это не обеспечивает криптографической защиты. Для минимизации рисков:

  1. Шифрование перед сохранением — рекомендуется использовать библиотеку вроде crypto.subtle для симметричного шифрования токенов перед записью:
const encoder = new TextEncoder();
const data = encoder.encode('my-secret-token');
const encrypted = await crypto.subtle.encrypt(
    { name: 'AES-GCM', iv: window.crypto.getRandomValues(new Uint8Array(12)) },
    cryptoKey,
    data
);
await set('accessToken', encrypted, myStore);
  1. Изоляция данных — хранение токенов в отдельном хранилище помогает снизить вероятность случайного доступа другими частями приложения.

  2. Ограничение времени жизни — access-токены лучше хранить с учетом их срока действия. Можно хранить объект вида { token, expiresAt } и проверять актуальность перед использованием.

Обработка чувствительных данных

Idb-keyval подходит для хранения данных, которые не требуют строгой защиты на уровне операционной системы. Сюда входят:

  • Токены с ограниченным сроком действия.
  • Настройки пользователей.
  • Ненулевые идентификаторы сеансов или профилей.

Нельзя хранить в чистом виде: пароли, секретные ключи API или любые данные, которые при утечке могут дать полный доступ к учетной записи или серверу. Для таких целей требуется использование защищённого хранилища (например, Web Crypto или secure storage в мобильных приложениях).

Асинхронная работа и обработка ошибок

Idb-keyval полностью асинхронна. Для стабильной работы приложения необходимо использовать try/catch:

try {
    await set('refreshToken', 'xyz', myStore);
    const token = await get('refreshToken', myStore);
} catch (error) {
    console.error('Ошибка при работе с IndexedDB', error);
}

Это важно, так как IndexedDB может быть недоступна в приватном режиме браузера или из-за ограничений пользователя.

Организация структуры данных

Для удобства работы с токенами и связанными метаданными рекомендуется хранить их в виде объектов:

const accessData = {
    token: 'abc123',
    issuedAt: Date.now(),
    expiresIn: 3600
};

await set('accessData', accessData, myStore);

Такой подход упрощает проверку срока действия токена и управление несколькими типами токенов одновременно.

Советы по безопасности

  • Никогда не хранить чувствительные данные в localStorage вместо IndexedDB, так как localStorage доступен синхронно и более уязвим к XSS.
  • Использовать отдельное хранилище для критических данных, минимизируя влияние потенциальных ошибок.
  • При необходимости использовать клиентское шифрование, чтобы даже при доступе к IndexedDB данные оставались защищёнными.

Итоговая структура взаимодействия

  1. Создать кастомное хранилище через Store.
  2. Перед записью чувствительных данных выполнять шифрование.
  3. Сохранять токены и метаданные в виде объектов.
  4. Использовать асинхронные операции с обработкой ошибок.
  5. Разделять критические и некритические данные в разные хранилища.

Такой подход позволяет эффективно использовать Idb-keyval для хранения токенов и других данных, соблюдая базовые принципы безопасности и удобства работы.