feat: implement CSRF protection on RPC layer

Double-submit cookie pattern: backend generates csrf_token cookie on login
(non-HttpOnly so JS can read it), validates X-CSRF-Token header matches
cookie on all authenticated RPC calls. Returns 403 if missing/mismatched.
Frontend reads cookie and sends header automatically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-11 00:46:52 +00:00
parent b9efd1b3d0
commit a7653d4c8b
3 changed files with 100 additions and 14 deletions

View File

@@ -15,6 +15,11 @@ export interface RPCResponse<T> {
}
}
function getCsrfToken(): string | null {
const match = document.cookie.match(/(?:^|;\s*)csrf_token=([^;]+)/)
return match ? match[1]! : null
}
class RPCClient {
private baseUrl: string
@@ -31,12 +36,18 @@ class RPCClient {
const timeoutId = setTimeout(() => controller.abort(), timeout)
try {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
}
const csrfToken = getCsrfToken()
if (csrfToken) {
headers['X-CSRF-Token'] = csrfToken
}
const response = await fetch(this.baseUrl, {
method: 'POST',
credentials: 'include', // Important for session cookies
headers: {
'Content-Type': 'application/json',
},
headers,
body: JSON.stringify({ method, params }),
signal: controller.signal,
})