乐闻世界logo
搜索文章和话题

How to implement CSRF protection in frontend frameworks (React, Vue, Angular)?

2月19日 19:13

CSRF protection in frontend frameworks (such as React, Vue, Angular) needs to consider framework characteristics and best practices to ensure effective security protection in Single Page Applications (SPAs).

CSRF Protection in React

1. Using CSRF Token

jsx
// Get CSRF Token import { useEffect, useState } from 'react'; function CSRFProtectedForm() { const [csrfToken, setCsrfToken] = useState(''); const [formData, setFormData] = useState({ name: '', email: '' }); useEffect(() => { // Get CSRF Token from server fetch('/api/csrf-token') .then(res => res.json()) .then(data => setCsrfToken(data.csrfToken)); }, []); const handleSubmit = async (e) => { e.preventDefault(); try { const response = await fetch('/api/submit', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken // Send Token in request header }, body: JSON.stringify(formData) }); if (response.ok) { alert('Submission successful!'); } else { alert('Submission failed'); } } catch (error) { console.error('Error:', error); } }; return ( <form onSubmit={handleSubmit}> <input type="text" value={formData.name} onChange={(e) => setFormData({...formData, name: e.target.value})} placeholder="Name" /> <input type="email" value={formData.email} onChange={(e) => setFormData({...formData, email: e.target.value})} placeholder="Email" /> <button type="submit">Submit</button> </form> ); }

2. Using Axios Interceptors

jsx
import axios from 'axios'; // Create Axios instance const api = axios.create({ baseURL: '/api', withCredentials: true // Allow sending cookies }); // Request interceptor: automatically add CSRF Token api.interceptors.request.use(async (config) => { // For request methods that need CSRF protection if (['post', 'put', 'patch', 'delete'].includes(config.method)) { try { const response = await axios.get('/api/csrf-token'); config.headers['X-CSRF-Token'] = response.data.csrfToken; } catch (error) { console.error('Failed to get CSRF token:', error); } } return config; }); // Usage example function SubmitForm() { const handleSubmit = async () => { try { await api.post('/submit', { data: 'example' }); alert('Submission successful!'); } catch (error) { alert('Submission failed'); } }; return <button onClick={handleSubmit}>Submit</button>; }

CSRF Protection in Vue

1. Using Vue Router and Axios

vue
<template> <form @submit.prevent="handleSubmit"> <input v-model="formData.name" placeholder="Name" /> <input v-model="formData.email" placeholder="Email" /> <button type="submit">Submit</button> </form> </template> <script> import axios from 'axios'; export default { data() { return { csrfToken: '', formData: { name: '', email: '' } }; }, async created() { // Get CSRF Token const response = await axios.get('/api/csrf-token'); this.csrfToken = response.data.csrfToken; }, methods: { async handleSubmit() { try { const response = await axios.post('/api/submit', this.formData, { headers: { 'X-CSRF-Token': this.csrfToken } }); if (response.data.success) { alert('Submission successful!'); } } catch (error) { alert('Submission failed'); } } } }; </script>

2. Using Vuex to Manage CSRF Token

javascript
// store/csrf.js import axios from 'axios'; export default { namespaced: true, state: { token: null }, mutations: { SET_TOKEN(state, token) { state.token = token; } }, actions: { async fetchToken({ commit }) { try { const response = await axios.get('/api/csrf-token'); commit('SET_TOKEN', response.data.csrfToken); } catch (error) { console.error('Failed to fetch CSRF token:', error); } } } };

CSRF Protection in Angular

1. Using HttpClient Interceptors

typescript
// csrf.interceptor.ts import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; import { Observable, from } from 'rxjs'; import { switchMap } from 'rxjs/operators'; @Injectable() export class CsrfInterceptor implements HttpInterceptor { constructor(private http: HttpClient) {} intercept( req: HttpRequest<any>, next: HttpHandler ): Observable<HttpEvent<any>> { // For request methods that need CSRF protection if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) { return from(this.getCsrfToken()).pipe( switchMap(token => { const csrfReq = req.clone({ setHeaders: { 'X-CSRF-Token': token } }); return next.handle(csrfReq); }) ); } return next.handle(req); } private async getCsrfToken(): Promise<string> { const response = await this.http.get<{ csrfToken: string }>('/api/csrf-token').toPromise(); return response.csrfToken; } } // app.module.ts import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; import { CsrfInterceptor } from './csrf.interceptor'; @NgModule({ imports: [HttpClientModule], providers: [ { provide: HTTP_INTERCEPTORS, useClass: CsrfInterceptor, multi: true } ] }) export class AppModule {}

General Best Practices

1. Token Refresh Strategy

javascript
// General Token refresh logic class CSRFTokenManager { constructor() { this.token = null; this.tokenExpiry = null; } async getToken() { // Check if Token has expired if (!this.token || Date.now() > this.tokenExpiry) { await this.refreshToken(); } return this.token; } async refreshToken() { const response = await fetch('/api/csrf-token'); const data = await response.json(); this.token = data.csrfToken; this.tokenExpiry = Date.now() + 3600000; // Expire after 1 hour } clearToken() { this.token = null; this.tokenExpiry = null; } }

2. Error Handling and Retry

javascript
// Request with retry mechanism async function makeRequestWithRetry(url, data, maxRetries = 3) { let retries = 0; while (retries < maxRetries) { try { const token = await csrfTokenManager.getToken(); const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': token }, body: JSON.stringify(data) }); if (response.status === 403) { // Token may have expired, refresh and retry csrfTokenManager.clearToken(); retries++; continue; } return await response.json(); } catch (error) { retries++; if (retries >= maxRetries) { throw error; } } } }

3. Security Configuration

javascript
// Cookie configuration (server-side) res.cookie('sessionId', sessionId, { httpOnly: true, // Prevent XSS theft secure: true, // HTTPS only sameSite: 'strict', // Strictest CSRF protection maxAge: 3600000 // Expire after 1 hour });

Framework-Specific Considerations

React

  • Use Context API to share CSRF Token
  • Consider using React Query or SWR for request management
  • Clean up Token when component unmounts

Vue

  • Use Vuex or Pinia to manage Token state
  • Use Vue lifecycle hooks to get Token
  • Consider using VueUse's useFetch

Angular

  • Use HTTP interceptors to automatically handle Token
  • Use dependency injection to manage Token service
  • Use RxJS for async operations

CSRF protection in frontend frameworks needs to combine framework characteristics and best practices to ensure good user experience without sacrificing security.

标签:CSRF