vibeblame

Чеклист безопасности Next.js: 10 пунктов перед деплоем

Практический чеклист перед деплоем Next.js: source maps, утечки API-ключей, security headers, TLS, секреты в NEXT_PUBLIC_, server actions, CORS и SEO. К каждому пункту — быстрая проверка.

Задеплоить Next.js-приложение легко. Задеплоить его безопасно — вот этот шаг обычно и пропускают, особенно когда бóльшую часть кода сгенерировали за вас. Это практический чеклист перед деплоем: десять вещей, которые реально ломаются в Next.js-приложениях, почему каждая из них важна и быстрая команда для проверки.

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


1. Отключите source maps в продакшене

Source maps восстанавливают ваш минифицированный бандл обратно в исходные .tsx-файлы. Если они доступны публично, любой может прочитать ваш код прямо в DevTools — включая комментарии, внутреннюю логику и то самое место, где вы захардкодили что не следовало.

curl -I https://yoursite.com/_next/static/chunks/main.js.map
# Должно вернуть 404, а не 200

Полный фикс: /guides/source-maps-production


2. Уберите API-ключи из бандла

Всё, что попадает в браузер, доступно всем. Секретный ключ Stripe, ключ OpenAI или строка подключения к БД во фронтенд-бандле — это уже утечка, и единственный фикс — ротация ключа.

# Поищите в собранном бандле распространённые префиксы ключей
grep -rE "sk_live_|AIza|ghp_|xoxb-" .next/static
# Не должно ничего найтись

Полный фикс: /guides/api-key-leaks


3. Добавьте security headers (CSP, HSTS, …)

По умолчанию Next.js не отдаёт ни Content-Security-Policy, ни HSTS, ни X-Frame-Options. Это оставляет вас открытыми для XSS, clickjacking и понижения протокола. Добавьте их один раз в next.config.js.

// next.config.js
const securityHeaders = [
  { key: "X-Frame-Options", value: "DENY" },
  { key: "X-Content-Type-Options", value: "nosniff" },
  { key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
]

module.exports = {
  async headers() {
    return [{ source: "/:path*", headers: securityHeaders }]
  },
}

Полный фикс: /guides/security-headers


4. Проверьте настройку TLS/SSL

Если вы на Vercel или Netlify — это сделано за вас. На своём сервере или прокси убедитесь, что у вас TLS 1.2+, валидный неистекающий сертификат и совпадающий домен.

echo | openssl s_client -connect yoursite.com:443 -servername yoursite.com 2>/dev/null | openssl x509 -noout -dates

Полный фикс: /guides/tls-ssl


5. Не выносите секреты в NEXT_PUBLIC_

Префикс NEXT_PUBLIC_ — это не мера безопасности, а наоборот. Он говорит Next.js встроить значение в клиентский бандл. Кладите туда только то, что не жалко напечатать на билборде (публичный publishable-ключ, публичный ID аналитики).

ПеременнаяКуда попадаетМожно секрет?
DATABASE_URLТолько сервер✅ остаётся приватной
NEXT_PUBLIC_API_URLВстраивается в браузер❌ публичная, никогда не секрет

Правило: если переменная с префиксом NEXT_PUBLIC_, считайте, что её прочитает весь мир.


6. Защитите server actions и route handlers

Server Actions и route handlers в app/api/* выполняются на сервере, но это всё равно публичные HTTP-эндпоинты. Их может вызвать кто угодно напрямую — не только ваш интерфейс. Проверяйте аутентификацию и права внутри экшена, не полагайтесь на то, что кнопка спрятана.

"use server"
export async function deleteAccount(id: string) {
  const session = await auth()
  if (!session) throw new Error("Unauthorized")
  if (session.userId !== id) throw new Error("Forbidden")
  // ... только теперь выполняем работу
}

7. Валидируйте env-переменные на этапе сборки

Пропущенная или опечатанная env-переменная не должна падать в продакшене в самый неподходящий момент. Валидируйте весь набор при старте, чтобы сборка падала сразу.

// env.ts
import { z } from "zod"

export const env = z
  .object({
    DATABASE_URL: z.string().url(),
    STRIPE_SECRET_KEY: z.string().startsWith("sk_"),
  })
  .parse(process.env)

Импортируйте env вместо чтения process.env напрямую — и плохой конфиг никогда не дойдёт до пользователей.


8. Закройте CORS

Если вы открываете API для других источников, не отражайте каждый Origin обратно с Access-Control-Allow-Origin: *, одновременно разрешая credentials — эта комбинация сливает аутентифицированные ответы любому сайту. Разрешайте явный список источников.

const allowed = ["https://yourapp.com"]
const origin = req.headers.get("origin")
if (origin && allowed.includes(origin)) {
  res.headers.set("Access-Control-Allow-Origin", origin)
}

9. Базовый SEO и мета-теги

Безопасность готова — не задеплойтесь невидимыми. Каждой странице нужны уникальный <title>, <meta name="description">, один <h1>, Open Graph-теги и canonical URL. Next.js делает это декларативно через экспорт metadata.

export const metadata = {
  title: "My Page",
  description: "Понятное описание на 120–160 символов.",
  alternates: { canonical: "https://yourapp.com/page" },
  openGraph: { title: "My Page", images: ["/og.png"] },
}

Полный фикс: /guides/seo-meta-tags


10. Просканируйте перед деплоем

Чеклисты легко не доделать. Самый быстрый способ убедиться, что вы реально закрыли все дыры, — просканировать задеплоенный URL и прочитать отчёт.

Вставьте свой продакшен-URL в vibeblame — он проверит source maps, утечки ключей, заголовки, TLS и SEO примерно за 30 секунд и выдаст готовый AI-промпт для фикса всего найденного.

Чеклист безопасности Next.js: 10 пунктов перед деплоем | vibeblame