每个请求生成 128 位随机 nonce 的严格 CSP,script-src 使用 'strict-dynamic' 且不含 'unsafe-inline','unsafe-eval' 仅在开发环境添加
nextjs-security-starter — Next.js 启动器模板
作者 calliarc
基于 Next.js App Router 的安全起步模板,内置 CSP nonce、安全响应头、Auth.js 会话认证、CSRF 防护、令牌桶限流与 Zod 输入校验,附带 Vitest 测试和 GitHub Actions 流水线。
看看你的网站会是什么样
浏览真实页面截图,比较内容排版与手机效果。点击下方缩略图切换,放大查看整页细节。
全部页面与视图 3
截图用于了解视觉与布局,交互效果请以实际项目为准。
值得关注的模板亮点
从已有项目资料中,快速了解它的特点。
安全响应头集中定义:HSTS、nosniff、Referrer-Policy、Permissions-Policy、COOP/CORP、frame-ancestors,并移除 X-Powered-By
Auth.js v5 认证:JWT 会话 8 小时、生产 Cookie 带 __Secure- 前缀,scrypt 密码哈希,登录按账号限流,回调 URL 仅接受同站地址
CSRF 防护:Server Actions 依赖 Origin 校验,Route Handlers 通过 secureRoute() 执行 Origin 检查与签名双提交令牌验证
令牌桶限流按客户端 IP 生效,登录突发 5 次后每分钟 5 次,/api/* 突发 30 次后每秒 1 次,响应带 RateLimit-Limit 与 RateLimit-Remaining
Zod 输入校验与安全错误处理,未知错误仅返回 requestId 和通用消息,不向客户端暴露堆栈
模板详细介绍
这是一个 Next.js 安全起步模板,README 标注状态为 working v0.1.0,模板可构建、测试通过,所列功能均已就位。它把常见 Web 安全机制集中到可复用的代码结构中:src/proxy.ts 为每个请求生成 128 位随机 nonce 并设置严格 CSP(script-src 使用 'strict-dynamic',不含 'unsafe-inline';'unsafe-eval' 仅在开发环境添加),同时负责安全响应头、按客户端 IP 的限流和乐观鉴权重定向。安全头统一在 src/lib/security/headers.ts 定义,由 next.config.ts 应用到所有路径。认证基于 Auth.js v5,使用 JWT 会话(8 小时有效期、每小时最多续签一次),生产环境 Cookie 带 __Secure- 前缀并设置 Secure、HttpOnly、SameSite=Lax;凭据提供方用 Zod 校验输入、scrypt 哈希密码,对未知邮箱也执行哈希以降低时序差异,登录按账号限流。CSRF 方面,Server Actions 依赖 Next.js 的 Origin 校验,Route Handlers 需用 secureRoute() 包装,执行 Origin 检查与签名双提交令牌校验。限流采用令牌桶,登录接口突发 5 次后每分钟 5 次,/api/* 突发 30 次后每秒 1 次。输入校验使用 Zod,错误处理通过 handleRouteError() 区分 Zod 错误、ApiError 与未知错误,不向客户端返回堆栈。模板还提供 /.well-known/security.txt(RFC 9116,Expires 始终为 180 天后)、CI 中的 npm audit、gitleaks 与 Dependabot。
限制与注意事项:README 明确说明 nonce 仅适用于动态渲染,根布局调用 connection(),因此没有页面会被静态预渲染。默认 MemoryStore 按进程工作,部署后重置且不跨实例或 Serverless 调用共享;多实例部署需自行基于 Redis 实现 RateLimitStore 接口,并用 Lua 脚本或 Upstash 的 @upstash/ratelimit 保持 consume 原子性。客户端 IP 取自 X-Real-IP / X-Forwarded-For,仅在会覆盖这些头的代理(如 Vercel、Cloudflare 或正确配置的 nginx / 负载均衡)之后可信。演示用户从环境变量读取,README 建议将 findUser() 替换为数据库查询,并考虑改用 argon2id 或 bcrypt。路线图中 Redis / Upstash 适配器、CSP 违规上报端点和 Playwright 端到端测试尚未完成。README 未提供性能数据、生产环境部署清单或托管平台的具体配置说明。
适合你的项目吗?
适用场景
- 需要为 Next.js App Router 项目快速搭建 CSP nonce、安全响应头与 CSRF 防护基础结构
- 希望参考 Auth.js v5 的凭据登录、会话 Cookie 配置与受保护路由实现
- 需要为登录和 API 端点添加按 IP 的令牌桶限流示例
- 想了解在 CI 中集成 npm audit、gitleaks 与 Dependabot 的配置方式
适合人群
- 使用 Next.js App Router 与 TypeScript 的开发者
- 需要可运行的安全机制参考实现而非生产成品的团队
- 准备自行替换演示用户存储并接入数据库的项目
- 关注 CSP、CSRF、限流与安全响应头配置细节的工程人员
上手与定制指南
结合仓库当前版本的说明,按下面的资料检查内容、配置与运行要求。
- 1
需要 Node.js 20.9 或更高版本(CI 使用 Node 22)与 npm;克隆仓库后执行 npm ci,并复制 .env.example 为 .env.local
- 2
使用 npx auth secret 生成 AUTH_SECRET,使用 npm run hash-password 生成 scrypt 哈希填入 DEMO_USER_PASSWORD_HASH
- 3
运行 npm run dev 后访问 /login,用 DEMO_USER_EMAIL 和已哈希的密码登录;/dashboard 展示 Server Action 表单与使用 CSRF 令牌的 Route Handler 表单
- 4
启用 GitHub 登录需创建 OAuth 应用,回调地址为 http://localhost:3000/api/auth/callback/github,并设置 AUTH_GITHUB_ID 与 AUTH_GITHUB_SECRET
- 5
多实例部署时默认 MemoryStore 不共享,需按 README 说明基于 Redis 实现 RateLimitStore 接口
授权与来源资料
使用条件与限制
免费使用 · 保留许可声明本次收录的是公开仓库中采用 MIT 许可的免费版本;免费范围为该版本代码,不代表外部服务或第三方素材免费。
使用时需要遵守
- 允许免费使用、修改、商用和分发该版本代码。
- 分发代码副本或实质性部分时,保留原作者版权声明和完整 MIT 许可声明。
- 代码按现状提供;担保与责任限制以原许可证及适用法律为准。
额外费用与待核对事项
- 演示图片、字体、图标及其他第三方素材需按各自许可核对,不能仅凭代码的 MIT 许可判断。
- 域名、托管、数据库、支付或 AI 等外部服务可能另外收费。
- Nonce 仅适用于动态渲染,根布局调用 connection(),因此没有任何页面会被静态预渲染。
- 默认 MemoryStore 按进程工作,部署后重置且不跨实例或 Serverless 调用共享;多实例部署需自行基于 Redis 实现 RateLimitStore 接口。
- 客户端 IP 取自 X-Real-IP / X-Forwarded-For,仅在会覆盖这些头的代理(如 Vercel、Cloudflare 或正确配置的 nginx / 负载均衡)之后可信。
- 演示用户从环境变量读取,需将 findUser() 替换为数据库查询,并考虑改用 argon2id 或 bcrypt。
- 启用 GitHub 登录需自行创建 OAuth 应用并设置 AUTH_GITHUB_ID / AUTH_GITHUB_SECRET。
- Redis / Upstash RateLimitStore 适配器尚未实现,仍处于路线图待办状态。
- CSP 违规上报端点(report-to)尚未实现,仍处于路线图待办状态。
- 针对认证与 CSRF 流程的 Playwright 端到端测试尚未实现,仍处于路线图待办状态。
查看原文依据
Permission is hereby granted, free of charge
许可证原文
- Nonces only work with dynamic rendering, so the root layout calls `connection()`. This means no page is statically prerendered.
README 原文
**Rate limiting in production:** the default `MemoryStore` works per process. It resets on deploy and is not shared across instances or serverless invocations. For multi-instance deployments, implement the `RateLimitStore` interface on top of Redis. Use a Lua script (or Upstash's `@upstash/ratelimit`) so that consume stays atomic, then pass that store to the `RateLimiter` instances.
README 原文
Client IPs come from `X-Real-IP` / `X-Forwarded-For`. These headers can only be trusted behind a proxy that overwrites them, such as Vercel, Cloudflare, or a correctly configured nginx or load balancer.
README 原文
The demo user is read from env vars. Replace `findUser()` with a database lookup, and consider argon2id or bcrypt through your user store.
README 原文
To enable GitHub sign-in, create an OAuth app with the callback `http://localhost:3000/api/auth/callback/github` and set `AUTH_GITHUB_ID` / `AUTH_GITHUB_SECRET`.
README 原文
- [ ] Redis / Upstash `RateLimitStore` adapter
README 原文
- [ ] CSP violation reporting endpoint (`report-to`)
README 原文
https://github.com/calliarc/nextjs-security-starter/blob/main/LICENSEhttps://github.com/calliarc/nextjs-security-starter/blob/main/README.md- [ ] End-to-end tests (Playwright) for auth and CSRF flows
README 原文
DeepSeek 根据仓库许可证和 README 整理 ·2026-10-14。结果仅覆盖已读取资料,依赖、图片、字体及后续条款变更以各自原文为准。
项目核对记录与介绍依据
模板资料
- 来源平台
- GitHub
- 资料与维护参考分
- 资料较完整 · 80 / 100
- 技术栈
- Next.js · React
- 网站类型
- 启动器
这个分数如何计算
本站按许可资料(最高30分)、演示链接(12分)、预览图(10分)、Star数(15分)、记录的维护时间(15分)、描述完整度(8分)、功能记录(5分)和分类资料(5分)计算。它不是代码、安全或性能测试,也不是 Google 评分;有链接不代表已实测可用。
这个项目需要核对什么
- 记录的仓库更新时间
- 2026-10-14
- 截图检查日期
- 2026-10-14
已收录演示链接。请用你的内容与屏幕尺寸检查;有演示不代表表单、认证或支付已经可用。
目录记录的主要技术栈是 Next.js。请通过依赖清单和锁文件核对实际版本与托管要求。这些说明基于收录资料,不代表代码审计或部署实测。
查看具体选型方法 →介绍的制作与核对状态
介绍由 AI 辅助整理目录与仓库资料。仓库作者不等于这篇介绍的审核者。
审核声明: codex-user-requested-batch-review-20261015 · 2026-10-15
查看当时使用的来源资料
SHA-256: 00d6bef6c891102781b7dd0866b6d4819a8bb93d434b4bab63286dcbfe32e26a
2026-10-14T23:37:38.851Z
来源文件 / 仓库# Next.js Security Starter
Next.js template with secure headers, rate limiting, CSRF protection and auth set up correctly.
[](https://github.com/calliarc/nextjs-security-starter/actions/workflows/ci.yml)
[](LICENSE)
[](https://github.com/calliarc/nextjs-security-starter/releases)
[](https://www.calliarc.com/)
> **Status:** working v0.1.0. The template builds, the tests pass, and every feature below is in place. Feedback and issues are welcome.
## Features
- Strict Content-Security-Policy with a fresh nonce per request (`'strict-dynamic'`, no `'unsafe-inline'`)
- Security headers configured in one place (HSTS, nosniff, Referrer-Policy, Permissions-Policy, COOP/CORP, frame-ancestors)
- Authentication with secure session cookies (Auth.js v5, credentials provider plus optional GitHub OAuth, protected `/dashboard`)
- CSRF protection for server actions and API routes (Origin check plus a signed double-submit token for Route Handlers)
- Rate limiting for login and API endpoints (token bucket with a pluggable store)
- Input validation with Zod and safe error handling (no stack traces reach clients)
- `/.well-known/security.txt` (RFC 9116)
- Dependency and secret scanning in CI (`npm audit`, gitleaks, Dependabot)
## Tech stack
- Next.js 16 (App Router, `proxy.ts`)
- TypeScript (strict)
- Auth.js (`next-auth` v5)
- Zod 4
- Proxy-based (formerly "middleware") rate limiting
- Vitest, ESLint, GitHub Actions
## Getting started
Requirements: Node.js 20.9 or later (CI uses Node 22) and npm.
```bash
git clone https://github.com/calliarc/nextjs-security-starter.git
cd nextjs-security-starter
npm ci
cp .env.example .env.local
```
Fill in `.env.local`:
```bash
# 1. Session signing secret
npx auth secret # or: openssl rand -base64 32 -> AUTH_SECRET=
# 2. Demo user password hash (the prompt hides your input)
npm run hash-password # paste the output into DEMO_USER_PASSWORD_HASH=
```
Then run the app:
```bash
npm run dev # http://localhost:3000
```
Sign in at `/login` with `DEMO_USER_EMAIL` and the password you hashed. The dashboard shows a Server Action form and a Route Handler form that uses a CSRF token.
To enable GitHub sign-in, create an OAuth app with the callback `http://localhost:3000/api/auth/callback/github` and set `AUTH_GITHUB_ID` / `AUTH_GITHUB_SECRET`.
### Scripts
| Command | What it does |
| --- | --- |
| `npm run dev` | Development server |
| `npm run build` / `npm start` | Production build and server |
| `npm run lint` | ESLint (`eslint-config-next` core-web-vitals + TypeScript) |
| `npm run typecheck` | `tsc --noEmit` |
| `npm test` | Vitest unit tests for the CSP, rate-limit, CSRF and validation helpers |
| `npm run hash-password` | Prints an scrypt hash for `DEMO_USER_PASSWORD_HASH` |
### Project layout
```
src/
proxy.ts # nonce + CSP, security headers, rate limiting, optimistic auth redirect
auth.ts # Auth.js config (providers, cookies, session, redirect guard)
lib/security/
csp.ts # nonce generation and CSP builder
headers.ts # every other security header, in one place
csrf.ts # Origin check and signed double-submit tokens
rate-limit.ts # token bucket, RateLimitStore interface, MemoryStore
password.ts # scrypt hashing
client-ip.ts # client IP used as the rate-limit key
lib/http/ # safe error responses, secureRoute() wrapper
lib/validation/ # Zod schemas and a size-limited JSON body parser
app/
.well-known/security.txt/ # RFC 9116 security.txt
api/csrf, api/messages # CSRF token endpoint and an example protected endpoint
login, dashboard # sign-in page and protected page with Server Actions
tests/ # Vitest unit tests
```
## Security features explained
### Content-Security-Policy with nonces
`src/proxy.ts` creates a 128-bit random nonce for every request. It sets the CSP on the response, and on the request as well, which is how Next.js finds the nonce and adds it to its own scripts and styles. The policy looks like this:
```
default-src 'self'; script-src 'self' 'nonce-…' 'strict-dynamic'; style-src 'self' 'nonce-…';
object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; upgrade-insecure-requests; …
```
- `'unsafe-eval'` is added **only** in development, because React's dev tooling needs it.
- Nonces only work with dynamic rendering, so the root layout calls `connection()`. This means no page is statically prerendered.
- To allow extra origins, use `cspDirectives({ extend: { "img-src": ["https://…"] } })`. The GitHub provider adds `https://github.com` to `form-action` automatically.
- API responses get `default-src 'none'; frame-ancestors 'none'`.
### Security headers in one place
All other headers are defined in `src/lib/security/headers.ts`. `next.config.ts` applies them to every path, and the proxy also applies them to the redirects and 429 responses it creates itself:
| Header | Value |
| --- | --- |
| `Strict-Transport-Security` | `max-age=63072000; includeSubDomains` (production only; `preload` is opt-in) |
| `X-Content-Type-Options` | `nosniff` |
| `Referrer-Policy` | `strict-origin-when-cross-origin` |
| `Permissions-Policy` | camera, microphone, geolocation, payment, usb, topics and others disabled |
| `X-Frame-Options` / CSP `frame-ancestors` | `DENY` / `'none'` |
| `Cross-Origin-Opener-Policy` / `-Resource-Policy` | `same-origin` |
| `X-Powered-By` | removed (`poweredByHeader: false`) |
### Authentication and session cookies
`src/auth.ts` configures Auth.js v5:
- JWT sessions last 8 hours and are re-issued at most once an hour.
- In production the cookies use the `__Secure-` prefix and are `Secure`, `HttpOnly` and `SameSite=Lax`.
- The credentials provider validates input with Zod and hashes passwords with scrypt. It runs the hash even for unknown emails, so response time does not reveal whether an account exists, and it returns the same error for a wrong email or a wrong password.
- The login is rate limited per account.
- The `redirect` callback and the login action only accept same-site callback URLs, which blocks open redirects.
- `/dashboard` is protected twice. The proxy does a quick cookie-presence redirect, and the page itself calls `auth()`. Server Actions and Route Handlers also call `auth()` themselves, because a proxy matcher is not a security boundary.
The demo user is read from env vars. Replace `findUser()` with a database lookup, and consider argon2id or bcrypt through your user store.
### CSRF protection
- **Server Actions:** Next.js only accepts `POST` for them and rejects any call whose `Origin` host differs from `Host` / `X-Forwarded-Host`. You don't need a token. If a reverse proxy rewrites the host, list the public host in `experimental.serverActions.allowedOrigins`. Note that a request with **no** `Origin` header is allowed through with a warning, so SameSite cookies are still your second layer.
- **Route Handlers:** wrap them in `secureRoute()` (`src/lib/http/secure-route.ts`). For unsafe methods it runs two checks:
1. **Origin check.** `Origin` (falling back to `Referer`) must match the app's own origin or an allow-list. `Sec-Fetch-Site: cross-site` is always rejected. `X-Forwarded-*` headers are ignored unless `TRUST_PROXY_HEADERS=true`.
2. **Signed double-submit token.** `GET /api/csrf` returns `<random>.<HMAC>`. It also sets the token in an `HttpOnly`, `SameSite=Strict` cookie, which is named `__Host-csrf` in production. The client sends the token back in `x-csrf-token`. The cookie and header must match, and the HMAC must verify against `CSRF_SECRET` (or `AUTH_SECRET` if `CSRF_SECRET` is not set).
If either check fails, the response is a generic `403`.
### Rate limiting
`src/lib/security/rate-limit.ts` implements a token bucket. Each key has a bucket of `capacity` tokens that refills at `refillPerSecond`. `src/proxy.ts` applies the limits per client IP:
- **Login** (`POST /login`, `/api/auth/callback/*`, `/api/auth/signin/*`): a burst of 5, then 5 per minute. `authorize()` applies the same limit per email address.
- **API** (`/api/*`): a burst of 30, then 1 request per second.
Responses include `RateLimit-Limit` and `RateLimit-Remaining`. Blocked requests get a `429` with `Retry-After`.
**Rate limiting in production:** the default `MemoryStore` works per process. It resets on deploy and is not shared across instances or serverless invocations. For multi-instance deployments, implement the `RateLimitStore` interface on top of Redis. Use a Lua script (or Upstash's `@upstash/ratelimit`) so that consume stays atomic, then pass that store to the `RateLimiter` instances.
Client IPs come from `X-Real-IP` / `X-Forwarded-For`. These headers can only be trusted behind a proxy that overwrites them, such as Vercel, Cloudflare, or a correctly configured nginx or load balancer.
### Input validation and safe errors
- Zod schemas live in `src/lib/validation/schemas.ts`. `parseJsonBody()` enforces `Content-Type: application/json`, a byte limit and valid JSON before it validates.
- `handleRouteError()` handles three cases:
- Zod errors: returns `400` with a list of field paths and messages.
- `ApiError`: returns its own status and a public message.
- Anything else: logs the full error server-side under a request id and returns `{ "error": { "code": "internal_error", "message": "Something went wrong.", "requestId": "…" } }`. Stack traces are never sent to clients.
- `error.tsx` / `global-error.tsx` show only the opaque `digest`. Server Action bodies are capped at 100 KB.
### security.txt
`/.well-known/security.txt` is served by a route handler. Its `Expires` field is always 180 days ahead. Set `SECURITY_CONTACT`, `SECURITY_POLICY_URL` and `APP_URL` to point it at your own disclosure process.
### CI and supply chain
`.github/workflows/ci.yml` runs these jobs on every push and pull request:
- lint, typecheck, test and build
- `npm audit --audit-level=high`
- a full-history gitleaks secret scan
Workflow permissions are read-only and checkout credentials are not persisted. Dependabot (`.github/dependabot.yml`) opens weekly updates for npm packages and GitHub Actions.
## Roadmap
- [x] Initial release
- [x] Documentation and examples
- [x] CI and automated tests
- [ ] Redis / Upstash `RateLimitStore` adapter
- [ ] CSP violation reporting endpoint (`report-to`)
- [ ] End-to-end tests (Playwright) for auth and CSRF flows
Have an idea? [Open an issue](https://github.com/calliarc/nextjs-security-starter/issues).
## Contributing
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).
## Changelog
See [CHANGELOG.md](CHANGELOG.md).
## License
[MIT](LICENSE) © 2026 CalliArc
---
Built and maintained by [CalliArc](https://www.calliarc.com/). Need help with secure application development? [Talk to our team](https://www.calliarc.com/services/managed-cyber-security/).
看看同类模板
对比同技术栈与用途的模板,找到更适合的视觉与内容结构。

ai-website-cloner-template
Clone any website with one command using AI coding agents
Next.js · 启动器

Next.js SaaS Starter
Next.js SaaS Starter 是 Next.js 官方维护的 SaaS 起点模板,定位介于学习资源和可直接部署的脚手架之间。
Next.js · SaaS

Next.js Commerce
Next.js Commerce 是 Vercel 团队维护的电商启动模板,基于 Next.js App Router 构建,采用服务端渲染、React Server Components、Server Actions …
Next.js · 电商

Next-js-Boilerplate
Next-js-Boilerplate 是一个面向 Next.js 16、Tailwind CSS 4 和 TypeScript 的启动器,核心定位是开发者体验优先。
Next.js · 启动器

tailwind-nextjs-starter-blog
tailwind-nextjs-starter-blog 是一个面向个人技术博客的 Next.js 与 Tailwind CSS 启动模板,其 v2 版本基于 App Router 与 React Server Comp…
Next.js · 博客

next-forge
Production-grade Turborepo template for Next.js apps.
Next.js · 启动器
