Introduction
Hello, in this post, we will briefly go over what CSRF is and how you can possibly avoid your users from being victims of the such attack. Recently, I have been working on the project for creating the backend of the website for selling books. While learning about how to basically handle authentication for safely allowing users to access the sensitive information, instead of using a cookie to store the credentials of a user, the instructor decided to go for a route of using HTTP headers for sending JSON web tokens in a request. When she went for that method, I couldn't initially understand why she would ditch a cookie for the storage of tokens for manually storing tokens somewhere in the browser - such as localStorage or sessionStorage, which may be vulnerable to XSS attacks. And then I realized there must be a reason for that, which led me down the path to search for an answer as to why a cookie may not be a good candidate for storing sensitive information. That's when I came across the topic of CSRF and how it may be used to make users perform unwanted actions.
CSRF?
CSRF is essentially an attack that tricks users into unknowingly performing nefarious actions wanted by an attacker. An attacker utilizes the credentials stored in the cookies of the browser of a user, and its malicious website, to potentially trick users into submitting requests to a legitimate website using its credentials. For example, a legitimate website issues and sends tokens to a user via cookies, which get stored in the user's browser for its subsequent requests. With the tokens saved in the browser, an attacker somehow leads a victim to its website, creates a form for submitting information to a legitimate website and makes a user submit the form for whatever purposes, such as changing one's password or making a purchase. As you can see, allowing such an action to an attacker is often very catastrophic and may lead to the complete compromise of the website itself - imagine an attacker somehow tricking a user with admin privileges to perform actions.
This is how it works:
- A user logs in to a legitimate website for whatever it intends to do.
- In response, a website issues tokens for allowing users to make subsequent requests to the various pages of the website. The purpose of the tokens is to allow users not to have to log in to the website every time it tries to access some pages that are only meant for authenticated users. A website issues tokens to a user via the cookies, which are stored in the browser of a user for making subsequent requests to the website.
- Unknowingly, an attacker lures a user to a page of the malicious website of an attacker that looks awfully similar to that of the legitimate website, and provides the form for making a POST request to the endpoint of a legitimate website. The form is meant to send data to the endpoint for changing the password of a certain user. Here is an example:
<!DOCTYPE html>
<html>
<head>
<title>My First Web Page</title>
</head>
<body>
<h1>Welcome to my first web page!</h1>
<p>This is a paragraph of text</p>
<form action="https://targetWebsite.com/api/change-password" method="post">
<input type="hidden" id="password" name="password" value="attackProvidedPassword1234">
<input type="submit" value="Click Here!">
</form>
</body>
</html>
- A user willfully clicks the button above to see what happens out of curiosity. At this point, it doesn't matter what information a user provides to the form, since an attacker is completely free to change the contents of the form via JavaScript, and may provide the new password of its choice -
attackProvidedPassword1234
- on behalf of a user. - A user ultimately sends a form to a legitimate website. In our example above, it sends the form to the website at the URL of a
https://targetWebsite.com/change-password
. A legitimate website handles the form, as if a user has willfully submitted the form, and proceeds to change the password of a user with the new password provided by an attacker.
The example above is kind of a simple example of what an attacker can do to a victim with CSRF attacks, but it is still an entirely feasible scenario that may result in catastrophic results. If an attacker manages to trick an admin into performing actions vital to the management of the system itself, it may result in the complete takedown of the system. So, since we know the mechanism of the attack, how do we exactly defend our users against falling victims to such an attack?
Solutions
One thing we have to know is that problems lie in the way the system is designed, so there is no way you can deflect some of the blames to a user when this attack occurs. There is no one-size-fits-all solution for completely mitigating the CSRF attacks, but rather it requires a combination of various measures that, when used together, provides a robust defense for end users. Here are some of the solutions you may implement in your system.
1. Avoid GET requests for making changes to data
- Stick with methods other than that of the GET for making changes to existing information in the system. The GET method is strictly used for retrieving the information, and it shouldn't be used for anything other than that. Imagine if there was a URL for sending money to a certain user like this,
http://bank.com/transfer.do?acct=MARIA&amount=100000
. The URL accepts two query parameters, acct and amount, and an attacker may easily construct a URL for sending a certain amount of money to itself by replacing the acct with its value, and may attack it to a link, such as<a href="http://bank.com/transfer.do?acct=MARIA&amount=100000">Click Here</a>
. All it is left at this point is for a user to click that link and send the money to an attacker.
2. Use CORS
- CORS allows the system to block requests from all the domains other than the ones that it is configured to accept requests from. The system often utilizes the HTTP methods such as POST and PUT to introduce or make changes to the data, and CORS essentially protects a user by filtering requests that are from the domains that are not approved by the system itself. Thankfully, the browsers nowadays are set up by default to avoid making the cross-origin requests, unless the target server allows it without any restriction.
3. Use CSRF Token
- Provide a single-use token to a user before every POST or PUT request a user makes. For example, when a user makes changes to its password, it submits its new password alongside the token provided by the system prior to changing the password. Once the token is used, it becomes invalid and prevents itself from being reused again. In my personal opinion, I don't know how effective this method is, when frontend and backend are decoupled, but I assume this may be very useful in a case where backend serves the HTML pages. Here is how you may use it to secure your webpage from attacks:
- Assign a session token to a user upon accessing the website.
- With a session token provided to a user, generate a CSRF token, which is essentially mapped to a session token of a user.
- A user uses it to submit a POST or PUT request to submit information, and the system verifies the CSRF token against a session token of a user to make sure that it is indeed from a user.
Top comments (0)