Аудит безопасности

Fresh — серверный фреймворк для Deno, ориентированный на рендеринг на сервере и минимизацию клиентского JavaScript. Это архитектурное решение напрямую влияет на модель угроз.

Ключевые особенности, формирующие поверхность атаки:

  • Отсутствие сборки: код выполняется практически в том виде, в каком написан.
  • Серверный рендеринг по умолчанию: HTML формируется на сервере.
  • Островная архитектура (Islands): JavaScript выполняется на клиенте только там, где это необходимо.
  • Deno Runtime: строгая модель разрешений и отсутствие node_modules.

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


Аудит маршрутов и обработчиков запросов

Маршруты во Fresh реализуются через файловую систему (routes/). Любой файл в этой директории автоматически становится HTTP-эндпоинтом.

Основные риски:

  • Непреднамеренно опубликованные маршруты
  • Отсутствие проверки HTTP-методов
  • Отсутствие валидации входных данных

Пример потенциально уязвимого обработчика:

export const handler = {
  async POST(req) {
    const data = await req.json();
    await saveToDb(data);
    return new Response("ok");
  },
};

Проблемы:

  • Нет проверки структуры data
  • Нет ограничения на размер тела запроса
  • Нет аутентификации или авторизации

При аудите необходимо:

  • Проверять каждый файл в routes/ на предмет публичности
  • Явно обрабатывать только допустимые HTTP-методы
  • Использовать строгую валидацию входных данных (schema-based)

Проверка XSS-уязвимостей

Fresh использует Preact и JSX, что по умолчанию экранирует HTML. Однако XSS возможен в следующих случаях:

Использование dangerouslySetInnerHTML

<div dangerouslySetInnerHTML={{ __html: content }} />

Любой HTML, поступающий извне, должен:

  • Проходить HTML-санитизацию
  • Иметь чётко определённый источник доверия

Формирование HTML-строк вручную

return new Response(`<h1>${title}</h1>`, {
  headers: { "content-type": "text/html" },
});

Если title формируется из пользовательского ввода — это прямой XSS.

Во время аудита:

  • Идентифицируются все места ручной генерации HTML
  • Проверяется происхождение данных
  • Анализируется использование dangerouslySetInnerHTML

CSRF и работа с формами

Fresh не навязывает собственный механизм защиты от CSRF. Любые POST, PUT, DELETE-запросы, изменяющие состояние, требуют явной защиты.

Типовой риск:

  • Использование cookie-based сессий без CSRF-токенов
  • Отсутствие проверки Origin / Referer

Рекомендуемые меры:

  • Генерация CSRF-токенов на сервере
  • Привязка токена к сессии
  • Проверка токена при каждом state-changing запросе
  • Установка cookie-флагов SameSite=Strict или Lax

Аудит аутентификации и авторизации

Во Fresh нет встроенной системы аутентификации, что перекладывает ответственность на разработчика.

Частые ошибки:

  • Проверка авторизации только на клиенте (в островах)
  • Отсутствие проверки прав доступа в серверных обработчиках
  • Использование JWT без проверки срока действия или подписи

Во время аудита необходимо:

  • Проверять, что каждый защищённый маршрут валидирует пользователя
  • Убедиться, что логика авторизации выполняется на сервере
  • Проверять корректность обработки токенов (JWT, session ID)

Безопасность Islands-компонентов

Islands — единственные места, где выполняется клиентский JavaScript. Это снижает риск XSS, но не устраняет его полностью.

Потенциальные проблемы:

  • Доверие данным, полученным из props
  • Использование eval, Function, динамических импортов
  • Работа с DOM напрямую

Аудит включает:

  • Проверку источников данных, передаваемых в острова
  • Анализ сторонних библиотек, используемых в islands
  • Проверку отсутствия небезопасных JS-конструкций

Управление зависимостями и supply chain

Fresh использует URL-импорты:

import { something } from "https://esm.sh/package@1.2.3";

Риски supply chain:

  • Обновление зависимостей без контроля
  • Использование непинованных версий
  • Зависимость от прокси-сервисов (esm.sh, skypack)

Во время аудита:

  • Проверяется фиксация версий в URL
  • Анализируется доверие к CDN
  • Проверяется отсутствие динамических импортов из пользовательских данных

Использование разрешений Deno

Deno предоставляет строгую модель безопасности через permissions:

  • --allow-net
  • --allow-env
  • --allow-read
  • --allow-write

Типовая ошибка — запуск приложения с избыточными разрешениями.

Аудит включает:

  • Анализ требуемых разрешений
  • Минимизацию флагов запуска
  • Проверку отсутствия чтения/записи файлов вне необходимости

HTTP-заголовки безопасности

Fresh не добавляет security headers автоматически.

Критически важные заголовки:

  • Content-Security-Policy
  • X-Frame-Options
  • X-Content-Type-Options
  • Referrer-Policy
  • Strict-Transport-Security

Пример усиления безопасности:

headers.set("Content-Security-Policy", "default-src 'self'");
headers.set("X-Content-Type-Options", "nosniff");

При аудите проверяется:

  • Наличие заголовков
  • Корректность CSP с учётом islands
  • Отсутствие unsafe-inline и unsafe-eval без необходимости

Логирование и утечки данных

Ошибки во Fresh часто обрабатываются напрямую через Response.

Риск:

  • Возврат stack trace в production
  • Логирование чувствительных данных
  • Отсутствие разделения dev/prod режимов

Аудит включает:

  • Проверку глобального error-handling
  • Анализ логов на наличие токенов, паролей, cookies
  • Проверку поведения при исключениях

Итоговая модель угроз Fresh-приложения

Fresh по умолчанию предлагает более безопасную базу, чем классические SPA-фреймворки, за счёт:

  • Минимального клиентского JS
  • SSR-first архитектуры
  • Runtime-безопасности Deno

Однако безопасность приложения полностью определяется качеством серверной логики. Аудит должен концентрироваться на маршрутах, обработке данных, разрешениях Deno и осознанном использовании islands, а не на клиентской части.