Hi everyone, I’m Shreya, and today I want to shed light on some lesser-discussed aspects of Cross-Site Request Forgery (CSRF). While identifying CSRF vulnerabilities during security assessments or bug bounties can often be straightforward, effectively mitigating them requires a deeper understanding of browser behavior, HTTP methods, and secure token handling. In this blog, I’ll share my learnings on how CSRF attacks actually work, why some requests are more vulnerable than others, and the modern strategies you can adopt—both on the client and server side—to strengthen your web application’s defense against CSRF.
Let’s get started from the basics.
Cross-Site Request Forgery (CSRF) is a critical web security vulnerability that exploits the trust a website has in a user’s browser. Often overlooked by developers, CSRF attacks can allow malicious websites to perform unauthorized actions on behalf of authenticated users—without their consent or awareness. This blog post dives deep into what CSRF is, how it works under the hood, and why it primarily affects GET and POST requests. We’ll also explore why HTTP methods like PUT are generally considered immune to CSRF and how modern browsers have evolved to defend against these attacks using secure cookie policies and built-in protections.
What is CSRF?
Imagine this: You’re logged into your bank account in one browser tab. In another tab, you visit a malicious website. That malicious site can silently submit a request — like transferring money — on your behalf to your bank, and your browser will attach your bank session cookie because it’s still valid. The bank thinks the request came from you.
Here’s how a CSRF attack typically works:
- User logs into a trusted site (e.g.,
example.com
) and obtains an active session via cookies. - Attacker lures the user to a malicious site (e.g.,
attacker.com
). This could happen through phishing emails, social media, or even ads. - The malicious site silently submits a request (e.g.,
GET
orPOST
) toexample.com
. - Browser automatically includes the session cookie, and the request appears valid to the server.
- The server executes the action, thinking it was initiated by the legitimate user.
Why CSRF Works with GET/POST But Not with PUT
A common question is: Why are GET and POST requests vulnerable to CSRF, while PUT and DELETE are not (or less so)?
The reason lies in how browsers behave by default, particularly in how they send requests and handle CORS (Cross-Origin Resource Sharing) and content types.
GET/POST: Vulnerable by Design
- GET requests can be triggered just by loading an image, iframe, or script.
- POST requests can be automatically submitted through hidden HTML forms using JavaScript or auto-submit mechanisms.
- Both allow browser cookies to be sent automatically without user interaction.
- These methods do not require preflight checks or any additional permissions, making them easy to exploit.
Example CSRF payload using a POST form:
<form action="https://example.com/delete-account" method="POST">
<input type="hidden" name="confirm" value="yes">
<input type="submit" value="Submit">
</form>
<script>document.forms[0].submit();</script>
This will silently send the form data to example.com
if the user is logged in.
Why PUT, DELETE, PATCH Requests Are Safer
1. CORS Preflight Requirement
When a browser sends a request with an “unsafe” HTTP method (e.g., PUT
, DELETE
), it first sends a preflight OPTIONS
request to the server to check permissions. If the server does not explicitly allow the origin, the actual request is blocked.
Example preflight behavior:
OPTIONS /update-profile HTTP/1.1
Origin: https://attacker.com
Access-Control-Request-Method: PUT
2. Content-Type Limitations
HTML forms can only submit a limited set of content types:
application/x-www-form-urlencoded
multipart/form-data
text/plain
However, many modern APIs require application/json
, which cannot be submitted via HTML forms without JavaScript — and cross-origin JavaScript is restricted by CORS.
3. No HTML Form Support for PUT
HTML forms do not support methods like PUT
or DELETE
. They only allow GET
and POST
, so a CSRF payload can’t trigger them easily without special scripts.
4. Same-Origin Policy Reinforcement
Even if the attacker tries to send a PUT
request via JavaScript, the browser’s same-origin policy prevents it from reading or interacting with responses unless the server explicitly permits it via CORS headers.
How Modern Browsers Help Prevent CSRF
To reduce the risk of CSRF, modern browsers now implement several built-in mechanisms that strengthen cookie behavior and reduce the chances of unauthorized cross-site interactions.
1. SameSite Cookie Attribute
Cookies can now include the SameSite
attribute, which restricts when cookies are sent in cross-site requests.
SameSite=Strict
: Cookies are sent only for same-site requests.SameSite=Lax
: Cookies are sent for top-level navigations (e.g., clicking a link).SameSite=None; Secure
: Cookies are sent cross-site, but only over HTTPS.
Example:
Set-Cookie: sessionid=xyz123; SameSite=Lax; Secure; HttpOnly
This helps prevent CSRF by ensuring cookies are not included in background requests from third-party sites.
2. Default to Lax
If no SameSite
is specified, modern browsers default to Lax
, offering protection by default against most background CSRF attempts, especially via images or silent requests.
3. Content Security Policy (CSP)
CSP allows you to define what content can be loaded on your site. With frame-ancestors
, you can prevent your site from being embedded in iframes — reducing clickjacking and CSRF via malicious UI embedding.
Example CSP:
Content-Security-Policy: frame-ancestors 'none';
4. Cross-Origin Resource Sharing (CORS)
Properly configured CORS headers let you define which external origins can access your resources. If a malicious site tries to make a cross-origin request, the browser blocks it unless it’s allowed.
Example:
Access-Control-Allow-Origin: https://yourdomain.com
5. Referrer Policy
A restrictive referrer policy minimizes the leakage of session or origin data when navigating across domains.
Recommended setting:
Referrer-Policy: strict-origin-when-cross-origin
6. Permissions Policy
Use the Permissions-Policy
(formerly Feature-Policy
) to disable unnecessary APIs like geolocation, camera, or microphone for embedded or framed content.
Example:
Permissions-Policy: geolocation=(), camera=(), microphone=()
Best Practices Summary
To secure your application against CSRF:
- Set cookies with
SameSite
,Secure
, andHttpOnly
. - Use CSRF tokens on all sensitive forms and API requests.
- Limit third-party embedding with
CSP
andframe-ancestors
. - Restrict cross-origin requests with
CORS
. - Minimize information leakage with a strong
Referrer-Policy
. - Disable unused browser features via
Permissions-Policy
.
Thats all for this post.Tune in to part 2 for more around CSRFs and how servers handles its generation, storage and validation.
Until then, Happy defending!