The CSRF vulnerability occurs when an attacker tricks a user’s browser into making an unintended request on a website where the user is authenticated. This can lead to actions being performed on behalf of the user without their consent.
Some example of unintended malicious requests could be to change the users password, make a fund transfer, etc.
For a successfully CSRF attack to occur, the website must have:
- Potential action that te attacker could use on its benefit (such as change password or email)
- Cookie-based session handling
- No unpredictable requests such as nonces or csrf tokens that the attacker can’t determine.
Imagine a website that when using the change password functionality, the POST request executed is this one:
1
2
3
4
5
6
7
POST /change-pwd HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
Cookie: session=yvthwsztyeQkAPzeQ5gHgTvlyxHfsAfE
new_pwd:newPassword123!
This requests is vulnerable to a CSRF because it uses a cookie to identify the session and there is not a unpredictable value such as the current password or a nonce.
An attacker could build this website:
1
2
3
4
5
6
7
8
9
10
<html>
<body>
<form action="https://vulnerable-website.com/change-pwd" method="POST">
<input type="hidden" name="new_pwd" value="AttackerPassword" />
</form>
<script>
document.forms[0].submit();
</script>
</body>
</html>
If the attacker delivers a link to this website and the victim enters, the form will be submitted automatically. Assuming that the session cookie from the https://vulnerable-website.com
doesn’t have the SameSite
attribute, the POST request to the change-pwd endpoint will be sent, using the victim’s session cookie and changing the password for another one that the attacker knows.
Defenses against CSRF
CSRF tokens are unique and unpredictable values generated by the server and shared with the client. When an action is performed, the client also submits this token. The server checks if the token received for that session is the correct one. If it is, it proceeds to execute the action. Since the attacker can’t predict the token, it is difficult to perform a successful CSRF attack.
SameSite cookies is a mechanism that the browsers have which determines when a website’s cookie have to bee included in requests originated from other sites. In other words, a cookie from X site won’t be included on a request to the X site if this request has been originated from an Y site if it has the SameSite
attribute.
What is a site in the context of SameSite cookies? A site is defined as the top level domain (TLD) such as
.com
,.net
, etc. plus one additional level of the domain name (TLD+1). It also consideres the scheme (protocol) used. For example:https://somewebsite.test.com
has the same site ashttps://anotherwebsite.test.com
but they both have a different site fromhttp://thirdwebsite.test.com
because of the scheme used and also fromhttps://somewebsite.test2.com
because it has another TLD+1.
Don’t confuse same site with same origin. Same origin is when everything in a two URLs is exactly the same, even the port. For example
https://somewebsite.test.com:443
andhttps://somewebsite.test.com:8080
are same site but not same origin.
Almost all browsers support the following SameSite restriction levels:
- Strict: browsers will not send it in any cross-site requests.
- Lax: browsers will send the cookie in cross-site requests, but only if both of the following conditions are met:
- The request uses the
GET
method. - The request resulted from a top-level navigation by the user, such as clicking on a link.
- The request uses the
- None: browsers will send this cookie in all requests to the site that issued it, even those that were triggered by completely unrelated third-party sites.
Developers can decide a restriction level for each cookie by just including the SameSite
attribute in the Set-Cookie
header:
Set-Cookie: session=0F8tgdOhi9ynR1M9wa3ODa; SameSite=Strict
Referer-based validation is when the application uses the HTTP Referer
header to verify that the request originated from the application’s own domain.
However, these protections can be bypassed in some situations:
Bypassing CSRF token validation
Even if the site includes CSRF tokens, it doesn’t imply that they are correctly used. Some websites only validate the token if the request is a POST
method, however, the endpoint may still work with the GET
method without checking the token.
Other sites, only validate the token if it is present in the request, but if you intercept it and delete the parameter, you can bypass the restriction.
It is also possible that the token is not tied to a specific session. Instead, the app maintains a list with all the issued tokens. In this situation, the attacker could provide its valid csrf and perform the desired action.
This example of website adds a csrf token and its value is the token assigned to the attacker. However, since it is a valid token not tied to a session, when a victim access to this website it will trigger the POST request using the attackers csrf token and its email will be changed without noticing.
Other implementations may send the token twice in the request: as a parameter and as a cookie. This avoids the server to track the tokens in the server side. When it receives the request, it just compares the cookie in the parameter with the one in the cookie.
Implementations such as this one may be vulnerable if the website contains a cookie setting functionality, because the attacker can choose a token, leverage the cookie-setting behavior to place their cookie into the victim’s browser and then perform the CSRF attack using the invented token.
Bypassing SameSite cookies
As explained previously, a Lax restriction allows to send the cookie in a cross sites if the request is a GET
and it is triggered by a top-level navigation. Some websites my have an endpoint configured in a way that accepts GET
and POST
requests. If this is the case, as long as the request involves a top-level navigation, the browser will still include the victim’s session cookie.
You can also try to overwrite the method using the
_method
parameter or theX-HTTP-Method-Override
header. APOST
to/wp-json/wp/v2/posts/42?_method=DELETE
would be translated to aDELETE
to thewp/v2/posts/42
route.
Some browsers such as Chrome, set the Lax restriction by default. However, to avoid breaking SSO functionalities, it is not enabled until the first two minutes after the first POST
request, hence, an attacker may have a two minutes window to exploit a CSRF attack. To avoid timing an attack, the attacker can try using another functionality, such as manually triggering the OAuth flux again to refresh the cookie.
Bypassing Referer-based validation
The HTTP Referer header is an optional request header that contains the URL of the web page that linked to the resource that is being requested. It is generally added automatically by browsers but you can configure the website to avoid adding it.
If the validation only occurs if the header is present, an attacker could host a malicious website with this meta tag: <meta name="referrer" content="never">
the Referer header will be dropped, bypassing the validation.
Another weak implementation occurs when the server just validates if their domain is present in the Referer header, or if it starts with an expected value. In these situations the attacker can create their own domains, adding the expected domain as a subdomain of their own malicious domain, or placing it elsewhere, such as a parameter.
Most browsers strip the query string from the Referer header by default, but you can override this behavior by ensuring that the response of the attacker website contains the
Referrer-Policy: unsafe-url
header.