aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Web Development

What Is CSRF and How Web Form Protection Works

While a user is logged into your site, another malicious page can send requests to your server on their behalf; that is the essence of the question what is CSRF. Cross-Site Request Forgery is an attack that exploits the browser's habit of attaching cookies to every request automatically. As long as the user's session is active, an attacker can "borrow" their authority to trigger state-changing actions such as changing a password, transferring money, or updating settings. In this article I explain how the attack works, the logic behind tokens, and how modern frameworks automate this defense, all with concrete examples.

How the Attack Works Step by Step

Suppose a banking app performs a money transfer with a form like this:

<form action="https://bank.com/transfer" method="POST">
  <input name="recipient" value="...">
  <input name="amount" value="...">
</form>

If the user visits a completely different page while still logged into the bank, that page can host a hidden form:

<form action="https://bank.com/transfer" method="POST" id="evil">
  <input type="hidden" name="recipient" value="attacker">
  <input type="hidden" name="amount" value="10000">
</form>
<script>document.getElementById('evil').submit();</script>

When the browser sends the request, it automatically includes the session cookie registered for the bank. From the server's point of view, the request looks exactly like one from a legitimate user. The root of the problem is this: the server cannot tell whether the request truly came from its own page or from a foreign origin.

Token Logic: The Synchronizer Token

The classic defense is the "synchronizer token pattern." The server generates an unpredictable random value for each session, stores it in the user's session, and embeds it in the page's form as a hidden field:

<form method="POST" action="/transfer">
  <input type="hidden" name="_token" value="a1b2c3...random">
  ...
</form>

When the form is submitted, the server compares the incoming _token with the value stored in the session. If they do not match, the request is rejected. The attacker's foreign page cannot know this token, because a page from another origin cannot read the bank page's content due to the Same-Origin Policy. The token stays secret, and the forged request becomes invalid.

For a token to be secure it should have these properties:

  • Unpredictable: created with a cryptographically strong random generator.
  • Bound to the session or user: one user's token must not be valid for another.
  • Required only for state-changing requests: read-only requests like GET should have no side effects anyway.

The Double Submit Cookie Method

For stateless APIs that do not want to keep session state on the server, there is an alternative pattern: double submit cookie. Here the token is written both to a cookie and to a request header (or body). The server checks whether the two are equal. A foreign site cannot read another origin's cookie via JavaScript to copy it into the header, so the attack fails. Its only drawback is that it requires careful configuration around issues like subdomain trust.

SameSite Cookies: Defense at the Browser Level

The SameSite attribute added to cookies tells the browser whether the cookie should be sent on cross-site requests. There are three values:

  • SameSite=Strict: the cookie is attached only to requests from the same site; it is not even sent when following an external link.
  • SameSite=Lax: it is attached to top-level navigation GET requests but not to cross-site POSTs. This is the default in most modern browsers.
  • SameSite=None; Secure: it is sent in all cases; use it when you genuinely need a cross-site cookie.

Lax or Strict provides a strong layer against CSRF, because the session cookie is never attached to an attacker-triggered cross-site POST. Still, SameSite alone is not considered sufficient; for older browsers and certain edge cases, using token protection alongside it is the most robust approach. Layered defense is essential.

How Frameworks Automate This

Modern frameworks handle token generation and validation for you. In Laravel, for example, the Blade @csrf directive adds the hidden token field to the form, and the VerifyCsrfToken middleware automatically validates it on every POST, PUT, PATCH, and DELETE request:

<form method="POST" action="/profile">
  @csrf
  <input name="name">
  <button>Save</button>
</form>

When making a request with JavaScript (for example fetch), you need to read the token from a <meta> tag and add it to the header:

const token = document.querySelector('meta[name="csrf-token"]').content;
fetch('/profile', {
  method: 'POST',
  headers: {
    'X-CSRF-TOKEN': token,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Aslain' })
});

The logic is the same across other ecosystems: Django uses {% csrf_token %} and CsrfViewMiddleware, Rails uses protect_from_forgery, and Express relies on csurf-style packages for the same job. APIs that do not use cookie-based sessions (for example those carrying an Authorization: Bearer header on every request) are naturally more resistant to CSRF, because the browser does not attach that header automatically.

Practical Checklist

  • Protect every state-changing endpoint (POST/PUT/PATCH/DELETE) with CSRF validation.
  • Add SameSite=Lax (or Strict where appropriate) and Secure to session cookies.
  • Never leak the token in a URL or log; use a hidden form field or request header.
  • Keep GET requests side-effect free; do not use them to mutate data.
  • Do not disable the framework's built-in protection; if you truly must, exempt only the specific route.

Frequently Asked Questions

Are CSRF and XSS the same thing?

No. XSS is when an attacker injects malicious script into your page and can even bypass token protection. CSRF is abusing the user's existing session from the outside. If an XSS vulnerability exists, your CSRF defense can collapse too, which is why both must be addressed together.

Does using HTTPS alone prevent CSRF?

No. HTTPS encrypts data and makes man-in-the-middle harder, but it does not care where the request originates. You still need tokens and/or SameSite cookies for CSRF.

Should the token change on every request?

Not necessarily. A token that is fixed for the session but bound to it is sufficient in most cases. A token regenerated on every request adds extra security but can cause problems with the back button and multi-tab use; that is why most frameworks use a single token for the lifetime of the session.

Want to secure your forms or audit an existing application? I build practical solutions for CSRF, XSS, and session security. Get in touch and let's harden your project together.

Bu kategorideki tüm yazılar →

Devamı için