feat: add CSRF protection for admin API routes
Double-submit cookie pattern: login sets bh-csrf-token cookie, proxy.ts validates X-CSRF-Token header on POST/PUT/DELETE to /api/admin/*. New adminFetch() helper in src/lib/csrf.ts auto-includes the header. All admin pages migrated from fetch() to adminFetch(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -63,4 +63,10 @@ function verifyTokenNode(token: string): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
export const CSRF_COOKIE_NAME = "bh-csrf-token";
|
||||
|
||||
export function generateCsrfToken(): string {
|
||||
return crypto.randomBytes(32).toString("base64url");
|
||||
}
|
||||
|
||||
export { COOKIE_NAME };
|
||||
|
||||
17
src/lib/csrf.ts
Normal file
17
src/lib/csrf.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
const CSRF_COOKIE_NAME = "bh-csrf-token";
|
||||
|
||||
function getCsrfToken(): string {
|
||||
const match = document.cookie
|
||||
.split("; ")
|
||||
.find((c) => c.startsWith(`${CSRF_COOKIE_NAME}=`));
|
||||
return match ? match.split("=")[1] : "";
|
||||
}
|
||||
|
||||
/** Wrapper around fetch that auto-includes the CSRF token header for admin API calls */
|
||||
export function adminFetch(url: string, init?: RequestInit): Promise<Response> {
|
||||
const headers = new Headers(init?.headers);
|
||||
if (!headers.has("x-csrf-token")) {
|
||||
headers.set("x-csrf-token", getCsrfToken());
|
||||
}
|
||||
return fetch(url, { ...init, headers });
|
||||
}
|
||||
Reference in New Issue
Block a user