As a developer, when you process a request from a user, how do you know that the person making the request is the legitimate user? If no systems are in place to ensure that the legitimate account owner is making the request, your web application could be vulnerable to cross-site request forgery (CSRF) attacks. Here is how you identify vulnerable code and what you can do to protect your application and your users.
What is a Standard Server Request?
Before getting into a CSRF attack, you should first understand what a standard server response looks like. Server responses for basic form submissions are usually either a POST or GET request. There are other request types, but the main types necessary for understanding CSRF attacks are POST and GET.
The following is an example of a POST request during a form submission:
POST /password/change HTTP/1.1
In the above request, the POST data is sent to the /password/change endpoint on the application located at yourwebsite.com. This endpoint processes the information sent to your web application. In this example, a new password is sent to the server. The session value is stored in a cookie, and it’s used to identify the user. However, what happens if an attacker can trick a user into submitting a password change by submitting a malicious form on an attacker-controlled web page? In this scenario, the attacker would then be able to change the user’s password, because no other verification is done to ensure that the POST request is the user who owns the account. If the from submits from the user’s browser, the session cookie stored on the user’s device is sent with the request, which is used to identify the user and validate the change.
Crafting a CSRF Attack
Before crafting an attack, a threat actor will perform reconnaissance and test your application to find the CSRF vulnerability. You might notice the scans when your application has several password requests focused on changing passwords. Since the attack occurs from the user’s browser on their device, the session cookie is sent with the malicious request on the web application, which might not be sent when the attacker scans the application indicating that it’s a malicious scan.
After identifying a CSRF vulnerable site, an attacker would craft a basic HTML document that might look like the following:
<form action=”https://yourwebsite.com/email/change” method=”POST”>
<input type=”hidden” name=”password” value=”mypassword” />
In the above HTML document, a web form is set up that includes a hidden variable with the attacker-chosen password. The HTML document automatically submits the form when the user opens the page, so the next step is to convince a user to open the HTML document in a browser. An attacker can use numerous methods to trick users such as adding the form to an attacker-controlled website or sending a link in email. File attachments in email can also be used to open HTML documents in a browser.
If an attacker can gain access to a user’s cookies, then the password change request can also be done by hijacking the session cookie. Session tokens should be considered sensitive data when building a web application, so browsers have built-in features to protect them. Cross-site scripting (XSS) is one type of attack that can result in theft of user session tokens stored in cookies.
With a successful CSRF attack, the attacker can perform any action processed on your web application. In this example, the user’s password is changed to a value known to the attacker, which could then lead to account takeover.
Preventing CSRF in Your Web Applications
Because the main issue with CSRF attacks is that there is no validation from the user’s side, the web application must perform validation before allowing any changes to an account. Validation is performed using a CSRF token. A CSRF token is a cryptographically secure randomly generated value attached to every form and request that changes account data.
When the application presents a web form in the user’s browser, the CSRF value is included as a hidden variable in the web form. The token looks similarly to a session value, but it’s distinct from the session. A form request with a CSRF token would look like the following:
POST /password/change HTTP/1.1
Cookie: session= HsAPsztygTvlfevthyxHwfEyzeQkAQ5g
In the above example, notice that the CSRF token and session are two separate cryptographically generated values. The application must check that the CSRF token matches that of a legitimate user before changing the user’s password.
Every request that makes account changes should include a token, but some applications skip token validation if no token is presented. It’s common for developers to base validation on the REFERER header, which can be spoofed by an attacker. If the application skips the CSRF token validation process, the token is rendered useless as it can be bypassed by an attacker.
Finally, the CSRF token should be tied to the user session to ensure that validation only passes if the token matches that of the user making the request. The CSRF token should also not be stored in a cookie, because this would render the validation useless as the cookie would be sent to the application from the attacker-controlled HTML document. Without user session validation, an attacker can send any CSRF token and make changes to a random account.
When you build a web application, cybersecurity should always be a priority. Any exploit that affects the safety of your user data should be considered when coding a web application. A CSRF token is one method of ensuring that attackers cannot obtain access to user accounts.