feat(security): rate-limit /api/flows/start, CSRF double-submit cookie, CSP headers
- Rate-limit /api/flows/start to 10 req/min per user (in-memory, matches login pattern) - Add middleware.ts: validates x-csrf-token header against csrf_token cookie on all API POST requests; issues the cookie on GET if missing; sets CSP, X-Frame-Options, X-Content-Type-Options, and Referrer-Policy on all responses - Add lib/csrf.ts: client-side apiFetch() wrapper that injects the CSRF header - Update all client components (login, useFlowRun, docker, caddy, git, systemd) to use apiFetch() for POST requests - Cookie config in login route already correct (NODE_ENV check, httpOnly, sameSite=strict) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1e31e3b584
commit
aa1fd41bec
11 changed files with 108 additions and 8 deletions
|
|
@ -8,12 +8,28 @@ export const dynamic = 'force-dynamic'
|
|||
const AGENT_URL = process.env.OPS_AGENT_URL ?? 'http://127.0.0.1:3099'
|
||||
const AGENT_SECRET = process.env.OPS_AGENT_SECRET ?? ''
|
||||
|
||||
const flowStartAttempts = new Map<string, number[]>()
|
||||
const MAX_FLOW_ATTEMPTS = 10
|
||||
const FLOW_WINDOW_MS = 60_000
|
||||
|
||||
function isFlowRateLimited(userId: string): boolean {
|
||||
const now = Date.now()
|
||||
const attempts = (flowStartAttempts.get(userId) ?? []).filter((t) => now - t < FLOW_WINDOW_MS)
|
||||
attempts.push(now)
|
||||
flowStartAttempts.set(userId, attempts)
|
||||
return attempts.length > MAX_FLOW_ATTEMPTS
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const user = await getCurrentUser()
|
||||
if (!user) {
|
||||
return Response.json({ error: 'unauthorized' }, { status: 401 })
|
||||
}
|
||||
|
||||
if (isFlowRateLimited(user.id)) {
|
||||
return Response.json({ error: 'Too many requests' }, { status: 429 })
|
||||
}
|
||||
|
||||
let body: { command_key?: string; args?: string[]; stdin?: string }
|
||||
try {
|
||||
body = await request.json()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue