Hacker's Perspective: A Modern Approach to Cross-Site Request Forgery
When I first began my journey into Application Security, I found it difficult to wrap my head around CSRF, Cross-Origin Resource Sharing, and cookie-based authentication. I set out to find the differences between client-side code, server-side code, browsers, and how the three interact with each other.
Below I’ll explain how they can all be used to locate and exploit Cross-Site Request Forgery within modern web applications.
To discover Cross-Site Request Forgery (CSRF) within a modern web application, you need to make sure the app is using cookies to authenticate users. This is because JWT’s (JSON Web Tokens) are not vulnerable to CSRF since they are not automatically added to cross-site requests like cookies are.
So, to make CSRF work you must find one of the following three occurrences:
Find an application that does a state-change within a GET request
Common state-changes I look for when testing are password resets, account invites, or user role changes. Even if the parameters are passed within POST data, it’s worth trying them as GET parameters and seeing if the app accepts them. If it does, you can often turn this into a CSRF because most session cookies are set with ‘SameSite=Lax’ (default in both Chrome and Firefox), meaning cookies are automatically passed within cross-site GET requests, but not POST requests.
CORS also should not be an issue here because our request does not qualify as ‘complex’, which means that CORS will not block the request – it will block the response.
For CORS to qualify a request as ‘complex’ it must meet one of these requirements:
- A request that uses methods other than GET, POST, or HEAD
- A request that includes headers other than Accept, Accept-Language or Content-Language
- A request that has a Content-Type header value other than application/x-www-form-urlencoded, multipart/form-data, or text/plain
If just one of the above cases is met, CORS will block the request from going through.
Note: if the application uses a CSRF token on the GET request, you could be stopped unless you find a CORS misconfiguration and retrieve the token. See number 2 for more details on that. You also need to make sure SameSite is not set to ‘Strict’, which means no cookies are attached in cross-site GET requests
Find an application with a CORS misconfiguration and a session cookie explicitly set with SameSite=None
The SameSite flag being set to None allows cookies to be automatically attached to cross-site POST requests. If the SameSite flag is not included when setting the cookie, Firefox and Chrome will automatically make it ‘SameSite=Lax’ which is why it must be explicitly set to ‘SameSite=None’ for this to work.
Find a Cross-Site Scripting vulnerability (my personal favorite)
Even if the site is using a CSRF token, you could grab that from the page and include it within the state-changing request. This is one of the reasons why XSS is so dangerous, but unfortunately often overlooked.
Cross-Site Request Forgery is still a valid and existing vulnerability in today’s Application Security landscape. Since it can be a complicated vulnerability, it is highly recommended to conduct a thorough penetration test of your application to ensure you are not vulnerable to one of the three above methods.