The most widely used method to prevent cross-site request forgery (CSRF) attacks is the implementation of anti-CSRF tokens. These are unique values generated by a web application and validated with each request to ensure authenticity. CSRF attacks exploit a user’s active session to execute unauthorized actions, such as redirecting them to a malicious website or accessing sensitive session data.
To effectively mitigate these risks, it is essential to generate, manage, and validate CSRF tokens correctly, ensuring robust protection against unauthorized requests.
What Is an Anti-CSRF Token?
An anti-CSRF token (also known as a CSRF token) is a security mechanism designed to verify the legitimacy of a user’s request. It works by assigning a unique, unpredictable token to the user’s browser, which must be included in subsequent requests. This ensures that the request originates from the authenticated user and not from an attacker. To be effective, the token must be cryptographically secure and resistant to guessing. The application must validate the token before processing any HTTP request, allowing only authorized actions within a user’s session.
What Is Cross-Site Request Forgery (CSRF)?
Cross-site request forgery (CSRF) is a web security vulnerability that enables an attacker to execute unauthorized actions on behalf of a legitimate user. In a typical CSRF attack, the attacker tricks the user into clicking a malicious link or visiting a compromised webpage, which then sends forged requests to a web application where the user is authenticated. Depending on the targeted application, a successful CSRF attack can manipulate user data, change account settings, or perform other unintended state-changing actions.
While there are multiple ways to implement anti-CSRF protection, the fundamental principle remains the same: ensuring that every request comes from a trusted source. To better understand how this works, let’s explore a basic example.
Example of a CSRF Vulnerability
Imagine you operate a web application hosted on www.example.com without any CSRF protection. Within this application, users can post messages to their profile by filling out a simple HTML form and clicking Submit:
<form action="/action.php" method="post">
Subject: <input type="text" name="subject"/><br/>
Content: <input type="text" name="content"/><br/>
<input type="submit" value="Submit"/>
</form>
When the user submits the form, their web browser sends a POST request to the server, transmitting the inputted data through the subject and content parameters:
POST /post.php HTTP/1.1
Host: example.com
subject=I am feeling pretty good today&content=I just ate a cookie, chocolate chip
Without CSRF protection, an attacker could exploit this by crafting a malicious webpage that silently submits a request on behalf of an authenticated user, potentially posting unwanted content or performing other unintended actions within the user’s session.
How a CSRF Attack Can Exploit a Vulnerable Web Application
If a user is logged into a web application and an attacker understands how requests are structured, they can exploit cross-site request forgery (CSRF) by tricking the user into unknowingly submitting a malicious request. This can be done by luring the user to visit a website controlled by the attacker, which then automatically executes an unauthorized action—such as posting an advertisement on the user’s profile.
For example, the attacker’s site could contain a hidden form like this:
<form action="https://example.com/action.php" method="post">
<input type="text" name="subject" value="Buy my product!"/>
<input type="text" name="content" value="To buy my product, visit this site: example.biz!"/>
<input type="submit" value="Submit"/>
</form>
<script>
document.forms[0].submit();
</script>
When the user visits the attacker’s site, the embedded JavaScript automatically submits the form, making their browser send the following POST request to the legitimate application:
POST /post.php HTTP/1.1
Host: example.com
subject=Buy my product!&content=To buy my product, visit this site: example.biz!
If the targeted site lacks CSRF protection, the request will be processed as if the user intentionally submitted it. Since the browser includes the user’s session cookie in the request, the server treats it as a legitimate action—without verifying its origin. This is what makes CSRF so dangerous: the server assumes the request is valid simply because it comes from an authenticated session, regardless of where it was triggered.
Implementing a Basic CSRF Token for Protection
To defend against CSRF attacks, a simple token-based mitigation strategy can be implemented. This involves generating a unique security token when a user logs in and ensuring that all form submissions within the application include this token. When properly generated and validated, this approach prevents unauthorized requests from being processed.
A secure form implementation might look like this:
<form action="/post.php" method="post">
Subject: <input type="text" name="subject"/><br/>
Content: <input type="text" name="content"/><br/>
<input type="hidden" name="csrf_token" value="dGhpc3Nob3VsZGJlcmFuZG9t"/>
<input type="submit" value="Submit"/>
</form>
On the server side, only POST requests containing the correct CSRF token should be accepted. A properly formatted request might look like this:
POST /post.php HTTP/1.1
Host: example.com
subject=I am feeling pretty good today&content=I just ate a cookie, chocolate chip&csrf_token=dGhpc3Nob3VsZGJlcmFuZG9t
By enforcing token validation, the server ensures that only legitimate users can submit requests. Attackers attempting to exploit CSRF by sending forged requests from an external site will fail because they cannot predict or access the valid user’s token. Since the server rejects any request lacking the correct token, unauthorized actions are effectively blocked.
Best Practices for Secure CSRF Token Generation and Validation
The method you use to generate and verify CSRF tokens should align with your application’s security requirements. Many modern web frameworks and programming languages provide built-in CSRF protection, and leveraging these features or a well-maintained external library is often the most reliable approach. If you need to implement CSRF protection manually, follow these key guidelines to ensure your tokens are effective:
- Use Cryptographically Secure Tokens – Tokens should be randomly generated using a cryptographic algorithm and be at least 128 bits in length to withstand brute-force attacks.
- Prevent Token Reuse – Each token should be tied to a specific user session and regenerated after sensitive actions. Expiring tokens after an appropriate time frame balances security and usability.
- Enforce Strict Token Validation – The server must validate tokens on every request using a secure comparison method (e.g., cryptographic hash comparison) to prevent manipulation.
- Avoid Exposure in URLs or Unencrypted Traffic – Never send CSRF tokens via GET requests or in unencrypted HTTP traffic. This prevents tokens from being leaked through server logs, browser history, or referrer headers.
- Leverage Secure Cookies – Storing CSRF tokens in SameSite cookies helps mitigate cross-site attacks. Additionally, using the HTTPOnly attribute prevents JavaScript-based exploits from accessing tokens.
- Mitigate XSS Vulnerabilities – Cross-site scripting (XSS) can allow attackers to steal or manipulate CSRF tokens. Ensuring your application is free from XSS flaws strengthens overall CSRF protection.
By adhering to these best practices, you can effectively prevent CSRF attacks and ensure that only legitimate user requests are processed by your application.
hash_hmac(‘sha256’, ‘post.php’, $_SESSION[‘internal_token’])
Implementing Different Levels of CSRF Protection
A basic CSRF protection mechanism involves generating a token when a user logs in, storing it in their session cookie, and requiring that token for all form submissions during the active session. This method can be effective, particularly when combined with session expiration policies. However, certain applications may require a more robust approach to enhance security.
Form-Specific CSRF Protection
For improved security while maintaining usability, you can generate a unique CSRF token for each form instead of relying on a single session-wide token. This approach ensures that even if one token is compromised, it cannot be used for unauthorized actions across multiple forms.
To implement this method:
- Generate a CSRF token internally but do not expose it directly to the user’s browser.
- Create a hashed version of the token combined with the form filename before sending it to the client. For example:
hash_hmac(‘sha256’, ‘post.php’, $_SESSION[‘internal_token’]);
- Verify the token on the server by regenerating the hash and comparing it with the submitted value. If the computed hash matches the one received, the request is considered valid, ensuring that the same form was used for submission.
By implementing form-specific CSRF protection, you further reduce the risk of token reuse attacks, enhancing overall security without compromising user experience.
Per-Request CSRF Protection
For applications requiring the highest level of security, such as online banking platforms, a per-request CSRF token strategy can be implemented. This approach involves invalidating each token immediately after it is verified, ensuring that every request requires a newly generated token. While highly secure, this method comes with notable usability challenges:
- Increased Server Load – Each request demands the generation of a new cryptographically secure token, which can impact server performance and resource availability.
- Limited Multi-Tab Functionality – Since each request requires a unique token, users cannot interact with the application across multiple browser tabs without triggering CSRF validation errors.
- Restricted Navigation – Users cannot rely on the browser’s back button for navigation, as revisiting a previous page would attempt to submit an expired token. Instead, they must use the application’s built-in navigation controls.
Stateless CSRF Protection with Double-Submit Cookies
In scenarios where server-side token storage is impractical, such as high-traffic applications with limited backend storage capacity, stateless CSRF protection can be implemented using the double-submit cookie pattern. This method eliminates the need for the server to store tokens while still providing an effective defense against CSRF attacks.
How Double-Submit Cookies Work
- Initial Token Generation – Before authentication, the server generates a random token and stores it in a cookie.
- Token Transmission – Each subsequent request must include this token in a hidden form field or custom HTTP header.
- Validation – The server verifies that the token received from the request matches the value stored in the user’s cookie.
There are two variations of this approach:
- Basic Double-Submit Token (“Naive” Approach) – The token is a random, unguessable value. The server simply checks for a match between the cookie-stored token and the token submitted with the request.
- Signed Double-Submit Token – The token is cryptographically signed using a server-side secret key, making it tamper-proof. Some implementations enhance security further by including timestamps in the token, allowing expiration-based validation.
While double-submit cookies reduce backend storage requirements, they do not prevent CSRF attacks if an attacker can execute JavaScript in the user’s browser (e.g., through XSS vulnerabilities). Therefore, this method should be used alongside other security measures, such as SameSite cookies and XSS mitigation strategies.
CSRF Protection for Asynchronous (Ajax) Requests
Modern web applications frequently use Ajax requests instead of traditional form submissions, which can complicate the implementation of standard CSRF tokens. A practical alternative is to include a custom request header in all Ajax requests that require CSRF protection. This header should contain a unique key-value pair that does not conflict with existing HTTP headers. On the server side, any incoming request without the expected custom header should be rejected to prevent unauthorized actions.
However, it is important to note that misconfigured CORS (Cross-Origin Resource Sharing) policies could allow attackers to set both cookies and custom headers, potentially bypassing CSRF protections. To mitigate this risk, ensure that CORS settings strictly limit access to trusted origins under your control.
Example: Automatic CSRF Protection in Ajax Requests
To enforce CSRF protection by default, you can override JavaScript’s XMLHttpRequest.open() method so that all outgoing requests automatically include a custom anti-CSRF header. Many popular JavaScript libraries and frameworks provide built-in mechanisms to achieve this, making it easier to integrate CSRF protection into Ajax-based applications.
Older security recommendations sometimes suggested that API endpoints do not require CSRF protection. However, as more applications are now fully API-driven, this advice is outdated. Just like with Ajax requests, API security can be strengthened by enforcing custom request headers to verify request authenticity and prevent CSRF attacks.
The Importance of Anti-CSRF Tokens for Login Forms
A common misconception is that CSRF protection is only necessary after a user logs in, leading some to believe that login forms do not require anti-CSRF tokens. While an attacker cannot directly impersonate a user before authentication, failing to secure the login process can still expose sensitive information and lead to account manipulation.
How an Attacker Can Exploit an Unprotected Login Form
- The attacker creates an account on your web application.
- They trick a victim into logging in using the attacker’s credentials—this can be achieved through social engineering tactics, such as sending a disguised login link.
- The victim unknowingly uses the application while logged into the attacker’s account instead of their own.
- The attacker monitors the victim’s activity, potentially gaining access to personal data, financial information, or tracking user interactions. In some cases, they may be able to initiate actions on behalf of the victim, such as making purchases using stored payment details.
To prevent this type of attack, CSRF protection should also be implemented on login forms, ensuring that only legitimate login attempts are processed.
CSRF Protection and XSS Mitigation Go Hand in Hand
While properly implemented anti-CSRF tokens are an effective defense against CSRF attacks, they are not foolproof if other vulnerabilities exist within the application. In particular, cross-site scripting (XSS) vulnerabilities can bypass CSRF protections by injecting malicious scripts that dynamically request and submit forms, automatically retrieving and using a valid CSRF token in the process.
To ensure a strong security posture:
- Regularly scan and test your web applications, APIs, and authentication flows for vulnerabilities, including CSRF and XSS.
- Implement strict input validation to prevent XSS attacks that could be leveraged to exploit CSRF protections.
- Use secure coding practices and security tools to detect and mitigate threats before they can be exploited.
A comprehensive security approach—covering CSRF prevention, XSS mitigation, and overall web application security—is essential to protect user data and prevent account manipulation.
Get the latest content on web security
in your inbox each week.