Fresh — фреймворк для Deno, изначально ориентированный на безопасность, предсказуемость и минимальное количество магии. Работа с переменными окружения в Fresh подчиняется философии Deno: явные разрешения, отсутствие неявного доступа к системе и строгий контроль над тем, какие данные доступны коду. Это делает тему безопасности переменных окружения принципиально важной.
Переменные окружения используются для хранения чувствительных данных: токенов API, ключей доступа к базам данных, секретов OAuth, параметров окружений (development, staging, production). Ошибки в их использовании приводят к утечкам, особенно в server-side rendering и edge-сценариях.
В Deno доступ к переменным окружения запрещён по
умолчанию. Для чтения Deno.env требуется явное
разрешение:
deno run --allow-env main.ts
Или более узко:
deno run --allow-env=DATABASE_URL,API_KEY main.ts
Ключевые особенности:
process.envDeno.env.get()Это исключает целый класс уязвимостей, характерных для Node.js-приложений, где любой зависимый пакет может прочитать все переменные окружения.
Fresh-приложение запускается через deno task start или
deno run. Обычно разрешения задаются в
deno.json:
{
"tasks": {
"start": "deno run --allow-net --allow-env --allow-read main.ts"
}
}
С точки зрения безопасности предпочтительно:
--allow-env без ограничений в
productionFresh чётко разделяет серверный и клиентский код. Это критично для безопасности переменных окружения.
Серверный код:
routes/*.tsroutes/*.tsx (в части обработчиков)islands — только частично (см. ниже)Клиентский код:
islands/*.tsx (код, выполняемый в браузере)Переменные окружения никогда не должны напрямую использоваться в клиентском коде. Любое значение, попавшее в JSX, сериализуется и отправляется в браузер.
Пример опасной ошибки:
export default function Page() {
return <div>{Deno.env.get("API_KEY")}</div>;
}
Даже если компонент кажется серверным, значение будет встроено в HTML-ответ.
Рекомендуемый подход — централизованный конфигурационный модуль:
// config/env.ts
export const DATABASE_URL = Deno.env.get("DATABASE_URL");
export const API_KEY = Deno.env.get("API_KEY");
С дополнительной валидацией:
function requireEnv(name: string): string {
const value = Deno.env.get(name);
if (!value) {
throw new Error(`Missing environment variable: ${name}`);
}
return value;
}
export const DATABASE_URL = requireEnv("DATABASE_URL");
Преимущества:
Islands в Fresh выполняются как на сервере (при первом рендере), так и в браузере. Это делает их особенно опасными с точки зрения переменных окружения.
Запрещённый паттерн:
export default function Counter() {
const secret = Deno.env.get("SECRET");
return <button>{secret}</button>;
}
Даже если значение используется только для логики, оно может попасть в сериализованное состояние.
Безопасное правило:
Если требуется использовать данные, зависящие от переменных окружения, используется серверная абстракция:
// routes/api/config.ts
export const handler = () => {
return new Response(
JSON.stringify({ featureEnabled: true }),
{ headers: { "Content-Type": "application/json" } },
);
};
Клиентский код работает только с производными данными, а не с самими секретами.
Deno не загружает .env автоматически. Для разработки
часто используется стандартная библиотека:
import "https://deno.land/std/dotenv/load.ts";
Особенности безопасности:
.env не должен попадать в репозиторий.env равноправны системным переменнымВ Fresh .env используется только на
сервере, при старте приложения.
В Deno Deploy переменные окружения задаются через интерфейс или CLI и
доступны через Deno.env.get.
Ограничения среды:
.envЭто снижает риск утечек, но требует строгой дисциплины в коде, особенно при использовании SSR.
Одна из распространённых уязвимостей — вывод переменных окружения в логах или ошибках.
Опасные примеры:
console.error(Deno.env.toObject());
throw new Error(`Config: ${JSON.stringify(Deno.env.toObject())}`);
Даже в закрытых логах это создаёт риск утечки через:
Безопасный подход:
Принцип наименьших привилегий применим и к переменным окружения:
SUPER_SECRETВ Fresh это усиливается за счёт разрешений Deno — можно ограничить доступ к конкретным именам переменных.
TypeScript позволяет снизить количество ошибок конфигурации:
interface Env {
DATABASE_URL: string;
API_KEY: string;
}
И последующая проверка при старте приложения. Это не защищает от утечек напрямую, но снижает риск неявного использования неправильных переменных.
Типовые угрозы:
--allow-envМеханизмы защиты в Fresh:
process.envFresh не скрывает работу с переменными окружения, а делает её максимально явной. Это требует дисциплины, но значительно повышает уровень безопасности при правильной архитектуре.