DEV Community

Ayako yk
Ayako yk

Posted on

Understanding CSRF Attacks: How They Work and How to Protect Your Website

In a previous blog post about cookies, I briefly mentioned CSRF attacks. In this article, I'll take a closer look and explore CSRF in more detail.

  1. What is CSRF
  2. What Users Might Suffer
  3. How CSRF Happens
  4. What Developers Should Do

What is CSRF?
CSRF stands for Cross-Site Request Forgery. According to Wikipedia:

[Cross-Site Request Forgery] is a type of malicious exploit of a website or web application where unauthorized commands are submitted from a user that the web application trusts.
Wikipedia

In simple terms, an attacker takes advantage of the trust a web application places in the user's browser. After a user is logged in and authenticated, such as by obtaining a cookie, the server assumes that all subsequent requests are legitimate. An attacker can abuse this by tricking the browser into sending unauthorized requests on the user's behalf.

What Users Might Suffer?
An attacker can exploit a user's authentication to perform unauthorized actions. This may include changing the user's information, such as their e-mail address or password, or initiating unauthorized financial transactions.

How CSRF Happens?
An attacker can exploit how browsers handle authenticated requests by embedding malicious forms or scripts into a webpage. This allows them to control the values submitted to a trusted server, such as changing a user's email address or initiating unauthorized financial transactions.

Example 1: Changing Emails
An attacker might include a form like the following on their malicious webpage:

<form action="https://vulnerable-website.com/email/change" method="POST"> 
    <input type="hidden" name="email" value="pwned@evil-user.net" /> </form>
Enter fullscreen mode Exit fullscreen mode

[PortSwigger](https://portswigger.net/web-security/csrf#:~:text=Cross%2Dsite%20request%20forgery%20(also,do%20not%20intend%20to%20perform.)

Example 2: Money Transaction
Imagine a user is logged into bank.com with an active session. If they accidentally visit evil.com, the attacker's webpage might include a form like this:

Image description

The Modern JavaScript Tutorial

In either case, when the form is submitted, the browser includes the session cookie, and the server, trusting it, processes the request as if it were made by the victim user.

How Does a User Accidentally Visit the Evil Site?
Some common examples include:

Phishing Emails
A user receives a phishing email containing a link that directs them to an evil site.

Malicious Advertisements (Malvertising)
While visiting a legitimate website, a user encounters an ad that directs them to an evil site when clicking.

Hacked Websites
A legitimate website may be hacked, and a link to an evil site could be embedded.

Typosquatting (Typo Domains)
A hacker creates domain names similar to a target website to deceive users.
e.g., bannk.com instead of bank.com

What Developers Should Do?
SameSite Cookies
The SameSite attribute, set in the Set-Cookie header, controls whether a cookie is sent with cross-site requests.

Briefly, a "site" is defined as the combination of:

  • A top-level domain (e.g., .com)
  • An additional level of the domain (e.g., example)
  • A scheme (e.g., https)

These requests are considered same-site requests:
From https://example.com to https://example.com
From https://app.example.com to https://intranet.example.com
From https://example.com to https://example.com:8080

Source and More Details: PortSwigger

SameSite=Strict
Cookies with the SameSite=Strict attribute are only sent with requests that originate from and target the same site. In simpler terms, the browser will only include the cookie if the request matches the site currently displayed in the browser's address bar.

SameSite=Lax
Cookies with the SameSite=Lax attribute are moderately restrictive. They allow cookies to be sent with cross-site requests, but only under the following conditions:

  1. The request uses the GET method.
  2. The request results from a top-level navigation, such as a user clicking a link (causing a change in the browser's URL address bar).

Since 2021, Chrome has applied SameSite=Lax restrictions by default when the SameSite attribute is not explicitly set. This behavior is becoming a standard among major browsers.

SameSite=None
Cookies with the SameSite=None attribute disable SameSite restrictions entirely, allowing the cookie to be sent with both cross-site and same-site requests. This is often useful for scenarios like tracking or when using third-party libraries. However, to ensure security, the Secure attribute must also be included.

Even if SameSite=Strict is set, attackers may bypass it by exploiting client-side redirects or URL manipulations that trigger same-site requests. When SameSite=Lax is set (or applied by default), cross-site requests using the GET method and triggered by top-level navigation are allowed, so attackers can exploit this to force a user's browser to make such requests.

CSRF Token
A CSRF token is a strong and widely used protection against CSRF attacks. It adds an extra layer of security by requiring a unique, unpredictable token that is difficult for attackers to guess.

Example:

<form name="change-email-form" action="/my-account/change-email" method="POST"> 
    <label>Email</label> 
    <input required type="email" name="email" value="example@normal-website.com"> 
    <input required type="hidden" name="csrf" value="50FaWgdOhi9M9wyna8taR1k3ODOR8d6u"> 
    <button class='button' type='submit'> Update email </button> 
</form>
Enter fullscreen mode Exit fullscreen mode

When the form is submitted, the POST request includes the CSRF token:

POST /my-account/change-email HTTP/1.1 
Host: normal-website.com 
Content-Length: 70 
Content-Type: application/x-www-form-urlencoded 

csrf=50FaWgdOhi9M9wyna8taR1k3ODOR8d6u&email=example@normal-website.com
Enter fullscreen mode Exit fullscreen mode

The server verifies the token, and if it's missing or incorrect, the request is rejected, preventing attackers from forging valid requests on behalf of the user.

PortSwigger

Limitations of CSRF Tokens
While CSRF tokens are effective, they are not 100% flowless. Attackers can sometimes bypass them by exploiting implementation flaws such as:

Switching request methods:
Some applications only validate CSRF tokens on POST requests but skip validation on GET requests. Attackers can exploit this by sending a malicious GET request instead.

Omitting the token parameter:
If an application only validates tokens when present but does not check if the token is missing, attackers can remove the entire CSRF token parameter from the request to bypass validation.

Not tying tokens to user sessions:
If the application accepts any valid token from a global pool rather than checking that the token belongs to the current user's session, an attacker can obtain a valid token by logging in with their own account and then reuse that token in an attack against another user.

There are several ways to protect against CSRF attacks, and it's best to combine multiple methods for stronger security. As developers, we need to understand how these systems work, continuously seek new solutions, and keep ourselves updated to stay ahead of attackers.

Top comments (2)

Collapse
 
nathan_tarbert profile image
Nathan Tarbert

tbh reading stuff like this always makes me double-check my own apps - never feels like enough protection. you ever feel like attackers are always one step ahead no matter what?

Collapse
 
ayako_yk profile image
Ayako yk

Thank you for your thoughtful comment! I completely understand —security often feels like an endless race. Staying updated with the latest information and continuously improving our defenses is definitely a priority.