Secure cookies

Fresh — фреймворк для Deno, ориентированный на серверный рендеринг и минимальный JavaScript на клиенте. Работа с cookies в Fresh происходит полностью на сервере, что делает их ключевым инструментом для аутентификации, хранения сессий и передачи небольших фрагментов состояния между запросами. Безопасность cookies в этом контексте имеет принципиальное значение, так как они автоматически отправляются браузером при каждом HTTP-запросе.

Fresh не навязывает собственную реализацию cookies, а опирается на стандартные HTTP-механизмы и утилиты Deno, что даёт полный контроль над параметрами безопасности.


Основные угрозы, связанные с cookies

Неправильно настроенные cookies могут привести к следующим проблемам:

  • XSS (Cross-Site Scripting) — кража cookies через доступ из JavaScript
  • CSRF (Cross-Site Request Forgery) — автоматическая отправка cookies на вредоносные запросы
  • Session Hijacking — перехват cookies при передаче по незащищённому соединению
  • Session Fixation — использование заранее известного значения cookie

Защита строится на корректной настройке атрибутов cookies и архитектуре серверной логики.


Ключевые атрибуты secure cookies

HttpOnly

Атрибут HttpOnly запрещает доступ к cookie из JavaScript (document.cookie). Это критично для защиты от XSS.

Set-Cookie: session=abc123; HttpOnly

В Fresh это означает, что даже при наличии интерактивных island-компонентов клиентский код не сможет прочитать или изменить cookie.


Secure

Атрибут Secure указывает браузеру отправлять cookie только по HTTPS.

Set-Cookie: session=abc123; Secure

В production-окружении Fresh почти всегда разворачивается за HTTPS (Deno Deploy, Cloudflare, Vercel), поэтому этот флаг должен использоваться по умолчанию для всех чувствительных cookies.


SameSite

SameSite определяет, будет ли cookie отправляться при кросс-сайтовых запросах.

Варианты:

  • Strict — cookie отправляется только при переходах внутри сайта
  • Lax — cookie отправляется при навигации (GET), но не при POST из других источников
  • None — cookie отправляется всегда (требует Secure)
Set-Cookie: session=abc123; SameSite=Strict

Для сессионных cookies в Fresh чаще всего используется Strict или Lax, что существенно снижает риск CSRF.


Path и Domain

  • Path ограничивает URL-пространство, где cookie будет доступна
  • Domain ограничивает домен и поддомены
Set-Cookie: session=abc123; Path=/; Domain=example.com

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


Установка cookies в Fresh

Fresh использует стандартный Response API. Cookies устанавливаются через HTTP-заголовок Set-Cookie.

import { Handlers } from "$fresh/server.ts";

export const handler: Handlers = {
  GET(_req, ctx) {
    const headers = new Headers();
    headers.append(
      "Set-Cookie",
      "session=abc123; HttpOnly; Secure; SameSite=Strict; Path=/",
    );

    return new Response("OK", { headers });
  },
};

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


Чтение cookies на сервере

Cookies доступны через заголовок Cookie входящего запроса.

const cookieHeader = req.headers.get("cookie");

Для удобства обычно используется парсер:

function parseCookies(cookieHeader: string | null) {
  if (!cookieHeader) return {};
  return Object.fromEntries(
    cookieHeader.split("; ").map((c) => c.split("=")),
  );
}

Такой подход подчёркивает сервероцентричную модель Fresh: все решения о доступе и валидации принимаются до рендера страницы.


Сессионные cookies и срок жизни

Для аутентификации часто применяются сессионные cookies, срок жизни которых ограничен:

Set-Cookie: session=abc123; Max-Age=3600

или

Set-Cookie: session=abc123; Expires=Wed, 21 Oct 2026 07:28:00 GMT

Короткое время жизни снижает риск использования украденного значения.


Удаление cookies

Удаление производится установкой того же имени cookie с истёкшим сроком действия:

Set-Cookie: session=; Max-Age=0; Path=/

В Fresh это реализуется тем же механизмом заголовков ответа.


Хранение чувствительных данных

Cookies никогда не должны содержать:

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

Обычно в cookie хранится только непрозрачный идентификатор сессии, а все данные находятся на сервере или в базе.


Подпись и шифрование cookies

Для защиты от подмены используется криптографическая подпись:

  • HMAC (например, SHA-256)
  • JWT (с осторожностью)

Пример логики:

  1. Создаётся значение сессии
  2. Подписывается секретным ключом
  3. Проверяется при каждом запросе

Даже при утечке cookie злоумышленник не сможет сгенерировать валидное значение.


Secure cookies и islands-архитектура Fresh

Islands в Fresh исполняются на клиенте, но не имеют доступа к HttpOnly cookies. Это естественным образом разделяет ответственность:

  • сервер — аутентификация, авторизация, работа с cookies
  • клиент — только отображение и интерактивность

Такая модель снижает поверхность атаки без дополнительных библиотек.


Типичные ошибки

  • отсутствие HttpOnly у сессионных cookies
  • использование SameSite=None без необходимости
  • хранение JSON-данных или токенов доступа напрямую в cookie
  • установка cookies без Secure в production
  • слишком широкие Domain и Path

Каждая из этих ошибок увеличивает риск компрометации сессий.


Практика безопасной конфигурации

Минимально безопасный набор для сессионной cookie в Fresh:

Set-Cookie: session=<id>; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600

Такое сочетание закрывает основные векторы атак и хорошо сочетается с архитектурой Fresh, где сервер является единственной точкой принятия решений.