Cross-Site Request Forgery happens when an attacker causes a victim’s browser to send an unwanted request to a site where the victim is already authenticated. The browser automatically includes the victim’s cookies, so the target application may treat the forged request as legitimate unless it has an independent way to verify intent. These notes cover the attack model, classic and asynchronous CSRF, token-based defenses, SameSite behavior, and common bypass conditions.
CSRF works because browsers automatically attach relevant credentials, usually cookies, when making requests to a trusted domain. If the application relies only on those credentials and does not verify that the request originated from a legitimate workflow, a forged request can succeed.
The victim does not need to type their password again. They only need to be logged in and tricked into loading the attacker’s content.
CSRF usually does not expose raw data directly, but it can still cause severe integrity damage.
The classic case is a forged form submission that triggers a state-changing action on a site where the victim is already logged in.
Typical vulnerable transfer form:
<form action="transfer.php" method="post">
<input type="text" name="to_account" required>
<input type="number" name="amount" required>
<button type="submit">Transfer</button>
</form>
If there is no anti-CSRF token or equivalent validation, an attacker can cause the victim’s browser to submit the same action from another page.
Modern applications often update account settings through background requests instead of full page reloads. The transport may be XMLHttpRequest or fetch, but the trust problem is the same.
If an authenticated endpoint accepts state-changing requests without a CSRF defense, a forged asynchronous request can still alter account state.
The browser does the dangerous part by attaching the authenticated cookies automatically.
The standard defense is to bind each state-changing request to a unique token that the attacker cannot guess and cannot cause the victim’s browser to generate correctly from another origin.
Example form with hidden token:
<input type="hidden" id="csrf_token" name="csrf_token" value="...token...">
On the server side, the request must be rejected if the token is absent, invalid, or mismatched.
A common pattern is the double-submit cookie technique. The application stores a token in a cookie and also places the same token in a hidden form field or request parameter. The server then verifies that both values match.
Typical validation idea:
if (base64_decode($_POST["csrf_token"]) == base64_decode($_COOKIE['csrf-token'])) {
// process request
}
This can work, but only if the token is unpredictable and the attacker cannot inject or override the cookie value.
Key point: a token is only a defense if it is both unique and hard to predict, and if the attacker cannot write the matching cookie or field value from a related origin.
The SameSite attribute controls when browsers send cookies with cross-site requests.
Secure.SameSite is useful, but it is defense in depth rather than a complete replacement for anti-CSRF tokens.
SameSite=Lax still allows cookies on top-level cross-site navigations using safe methods like GET. That means state-changing GET endpoints can remain exploitable.
Simple logout example:
<a href="https://target/logout.php" target="_blank">Survey Link!</a>
If the logout action depends only on cookies and is triggered by GET, Lax cookies may still accompany the request and the logout may succeed.
Strict where possible.