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

Как запретить сливать токен с ограниченным permission при небезопасном хранении?

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

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

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

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

Защита ограниченных токенов при небезопасном хранении

Это критичная проблема безопасности на фронтенде. Если токен с ограниченными правами лежит в localStorage или sessionStorage, его легко украсть через XSS. Давайте разберемся в стратегиях защиты.

Основная проблема

Если токен хранится в доступном хранилище, он может быть украден через:

  • XSS (выполнение чужого JS в контексте сайта)
  • CSRF (если хранится в localStorage)
  • DevTools (если пользователь инфицирован малваром)

Стратегия 1: Использование HttpOnly cookies

Это основная защита — браузер не дает JS доступ к cookie. На бэкенде:

response.set_cookie(
  auth_token,
  token,
  httponly=True,
  secure=True,
  samesite=Strict,
  max_age=3600
)

На фронтенде токен отправляется автоматически при включении credentials:

fetch("/api/user", {
  credentials: "include"
})

Плюсы:

  • XSS не может украсть токен
  • CSRF защищена через SameSite
  • Браузер управляет сроком действия

Стратегия 2: Разделение токенов (Access + Refresh)

Делим токены по назначению: access token живет мало (15 мин), refresh token — долго (7 дней). Оба в httpOnly cookies:

async function apiCall(url) {
  let response = await fetch(url, {
    credentials: "include"
  });
  
  if (response.status === 401) {
    await fetch("/api/refresh", {
      method: "POST",
      credentials: "include"
    });
    response = await fetch(url, {
      credentials: "include"
    });
  }
  
  return response;
}

Плюсы:

  • Access токен живет мало (даже если украдут, мало вреда)
  • Refresh токен в httpOnly (не видим JS)
  • Можно отозвать токен на бэкенде

Стратегия 3: CSRF токены для дополнительной защиты

Если нельзя использовать httpOnly cookies:

const csrfToken = document.querySelector('meta[name="csrf-token"]').content;

fetch("/api/update", {
  method: "POST",
  headers: {
    "X-CSRF-Token": csrfToken
  },
  body: JSON.stringify(data)
});

Бэкенд проверяет: если токен не совпадает с тем, что в cookie — отклоняет запрос.

Стратегия 4: Memory storage + auto-logout

Хранить токен только в памяти (теряется при перезагрузке):

let accessToken = null;
let inactivityTimer = null;

function setAccessToken(token) {
  accessToken = token;
  resetInactivityTimer();
}

function resetInactivityTimer() {
  clearTimeout(inactivityTimer);
  inactivityTimer = setTimeout(() => {
    accessToken = null;
  }, 30 * 60 * 1000);
}

Плюсы:

  • XSS не может украсть токен (только во время сессии)
  • Автоматический logout

Стратегия 5: Binding токена к браузеру

Связываем токен с уникальным ID браузера:

const deviceId = localStorage.getItem("device_id") || generateUUID();
localStorage.setItem("device_id", deviceId);

const response = await fetch("/api/login", {
  method: "POST",
  body: JSON.stringify({
    username,
    password,
    device_id: deviceId
  })
});

fetch("/api/data", {
  headers: {
    "X-Device-ID": deviceId
  },
  credentials: "include"
});

Плюсы:

  • Если украдут cookie, без device_id не помогает
  • Защита от replay атак

Рекомендуемый подход

Комбинация стратегий:

  1. Access token в httpOnly cookie (15 мин)
  2. Refresh token в httpOnly cookie (7 дней)
  3. CSRF токен через X-CSRF-Token заголовок
  4. Device binding через X-Device-ID заголовок
  5. SameSite=Strict на всех cookies
  6. Secure флаг (только HTTPS)

Результат на клиенте:

const response = await apiClient.post("/api/update", data);

Всё управляется внутри: cookies отправляются автоматически, CSRF токен добавляется автоматически, refresh происходит при необходимости.

Эта комбинация делает кражу токена практически невозможной и обеспечивает защиту от основных векторов атак на фронтенде.

Как запретить сливать токен с ограниченным permission при небезопасном хранении? | PrepBro