Intro to CSRF
What is CSRF
CSRF or Cross Site Resource Forgery is an exploit which takes advantage of a users session token when they are logged into an application to unbeknownst to user, act on their behalf.
In other words. Generally for a user to be able to access and modify their resources, the application generates a token for them during log in and saves it in the browsers storage. This token is used to authorise users requests to the server to retrieve or modify the data which the the application has given them access to.
CORS
Historically browsers followed same-origin policy which is a security concept where a web browser permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same origin — meaning, they have the same protocol, host name and port number.
But as the web grew and became a bit more intertwined same-origin policy turned out to be too restrictive as websites used content or resources for CSS or fonts from different sites.
As a standard, modern web apps are broken into units which all serve their own purpose. Usually there is at least 2 servers running — one which serves the bit the users interact with and second, which exchanges information about the current state of the database with the world and each have their own origin.
Now, given that I as an obscenely evil hacker have the potential to get access to the authorisation token of a user for a very important resource (e.g — a bank) I can change the state of that users data of that resource through my own evil website.
How is that implemented ?
Let’s say I have a website which allows authenticated users to post comments on carefully selected topics.
The backend of my app runs on url “api-of-opinions-about-very-important-things.com” and front-end runs on another server with url “opinions.com”
When a user posts a comment on my website, that comment is sent to the backend as a POST request with the payload of user id, comment and topic id and authorised with a token from browsers storage.
If that user enters another website which submits the same request with an evil comment to the backend, the user will be authorised and it will seem as if the user had posted that comment.
In my example I don’t have a form but some input and a button, When the request is sent it is possible to see request payload to the server from browser developer tools/ Network, which an attacker can mimic in their malicious script.


If the website used a form so send data it would also be possible to see what was sent from dev tools/ Network, gain some insight into database, copy that form and send it away with inputs filled in to attackers liking.
As an example I started a server of another origin (on another port on localhost) with create-react-app and put run a post request to opinions app server using token from localStorage for authorisation.

Ok, great, this worked, the terrible comment did end up at the my site but not for the right reasons.
Anyway.. as I went to look at my back end code I noticed that comments controller didn’t really do much with authorisation(this was an old project). I then logged out the token on the “malicious website” .. it was null! Apparently I got something mixed up about CSRF — it only works with cookies, Use JWT ! it might still be safe.
Ok. Let’s start again. CSRF works on cookies and if a cookie is saved you can submit a hidden form filled in in your evil website where you have lured your unsuspecting victims using brilliant social engineering.
Again, form can be created on the basis of the form from original website(also can be hidden), filled in with with whatever data and submitted on page load. It would most likely have method post or delete etc. whichever flavour of evil the attacker is feeling.
The takeaway is this — with CSRF attack, the hacker doesn’t get access to read any of your users data, all they can do is modify it and because it happens in the users browser it will seem like it was the user who made the change.
Another takeaway — Don’t give out actual user id’s encrypt them in a way so not anyone can send of a request using a likely user id starting from 1 to whatever.
How to protect against it
- Have the user authenticate themselves again with password before sending away the form
- Configure Access Control Allow Origin headers.
When a client sends a request to another origin to get some data back, the browser includes a request header Origin which indicates to the source of information where the request is coming from.
Weather or not any data is sent back is up to the server. For example by default when a ruby backend is made with rails new — api, Rack in application.rb is configured to allow all origins by default. If this is the case the server sends backAccess-Control-Allow-Origin: * in response header and response body. If in my broken example only ‘opinion.com’ would have been allowed, I would not have been able to modify anything from my hacky site.
There can be cases where Origin header is not present, in that case, check Referer header, if none are present it is recommended by OWASP to not let the request through.
3. With every form submit or request to change the application state, send an individual token which is cryptographically generated random number or string of characters unique to session
When a request is issued by the end-user, the server-side component must verify the existence and validity of the token in the request as compared to the token found in the session.
TODO :
* How JWT works
* Why is localStorage token not visible in other tabs vs cookies are visible
* How to really truly protect user ids
