Cross-Site Request Forgery (CSRF) and Protecting Your React Applications

Serhii Koziy
3 min readJan 20, 2025

Cross-Site Request Forgery (CSRF) is a common web security vulnerability that exploits the trust a website has in a user’s browser. As frontend developers, particularly when working with React or other modern frameworks, understanding CSRF and implementing proper defenses is crucial to safeguard your applications. This article explains CSRF, its potential impact, and effective strategies to protect your React (or any frontend) application, with examples in TypeScript.

What is Cross-Site Request Forgery (CSRF)?

CSRF is an attack where a malicious website tricks a user’s browser into performing actions on a target website without their consent. Since browsers automatically include cookies, including session cookies, with requests to a website, attackers can exploit this behavior to perform unintended actions as the victim.

Real-World Example

Imagine a banking application where users can transfer money via a POST request to https://bank.com/api/transfer. If the user's session cookie is valid and attached, an attacker can create a malicious website that sends the same POST request without the user's knowledge, potentially transferring funds to the attacker's account.

The attack works as follows:

  1. The user logs into https://bank.com and remains authenticated.
  2. The attacker tricks the user into visiting a malicious page.
  3. The malicious page sends a forged POST request to https://bank.com/api/transfer using the user's authenticated session.

Without proper CSRF protection, the backend server processes the request, believing it to be legitimate.

Key Concepts of CSRF Prevention

To prevent CSRF, the fundamental strategy is ensuring that requests originate from trusted sources. The most effective methods include:

  1. CSRF Tokens
  2. SameSite Cookies
  3. Custom Request Headers
  4. User Authentication Context

Let’s dive deeper into these methods and explore how to implement them in React with TypeScript.

CSRF Protection Techniques

1. CSRF Tokens

A CSRF token is a unique, unpredictable value generated for each user session and included in requests. The server verifies the token before processing the request.

Backend Setup

The backend generates a CSRF token and includes it in a response (e.g., as a cookie or in a response body).

Frontend Implementation in React (TypeScript)

Assume the backend sends a CSRF token in a cookie named csrf_token.

import axios from 'axios';

// Axios instance with CSRF token included
const apiClient = axios.create({
baseURL: 'https://bank.com/api',
withCredentials: true, // Ensures cookies are included
});
// Intercept requests to add CSRF token from cookies
apiClient.interceptors.request.use((config) => {
const csrfToken = document.cookie
.split('; ')
.find((row) => row.startsWith('csrf_token'))?.split('=')[1];
if (csrfToken) {
config.headers['X-CSRF-Token'] = csrfToken;
}
return config;
});
export default apiClient;

The server validates the X-CSRF-Token header against the token stored for the session.

2. SameSite Cookies

The SameSite attribute on cookies restricts them from being sent with cross-origin requests.

Backend Configuration

Ensure session cookies are configured with SameSite=Strict or SameSite=Lax.

  • Strict: The cookie is sent only for same-origin requests.
  • Lax: The cookie is sent with top-level navigation and GET requests initiated by third-party sites.

Example Configuration (Express.js):

app.use(session({
name: 'session_id',
secret: 'your-secret',
cookie: {
httpOnly: true,
secure: true, // Use in production
sameSite: 'Strict',
},
}));

No additional frontend code is required as the browser enforces these restrictions.

3. Custom Request Headers

By requiring custom headers in requests, you can block requests originating from malicious websites, as browsers prevent JavaScript on a different origin from setting custom headers.

Frontend Example in TypeScript

const apiClient = axios.create({
baseURL: 'https://bank.com/api',
headers: {
'X-Requested-With': 'XMLHttpRequest',
},
});

apiClient.post('/transfer', {
amount: 100,
toAccount: '12345',
});

The server verifies the X-Requested-With header to ensure requests are from trusted clients.

4. User Authentication Context

For highly sensitive actions, require the user to re-authenticate or confirm their identity (e.g., entering a password or OTP).

Frontend Example

Prompt the user for additional credentials before performing sensitive operations.

const handleTransfer = async () => {
const password = prompt('Enter your password to confirm:');

if (password) {
await apiClient.post('/transfer', {
amount: 100,
toAccount: '12345',
password,
});
}
};

The backend verifies the password or OTP before completing the action.

Conclusion

Cross-Site Request Forgery is a critical security vulnerability that every frontend developer must address. By implementing CSRF tokens, SameSite cookies, custom headers, and user authentication measures, you can significantly reduce the risk of CSRF attacks.

While the examples provided focus on React and TypeScript, these principles apply universally across frontend frameworks and libraries. Always ensure collaboration between frontend and backend teams to establish a comprehensive CSRF defense strategy.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet

Write a response