CSRF Protection
Cross-Site Request Forgery (CSRF) is a type of security vulnerability where an attacker tricks a user into performing actions on a web application where the user is authenticated. This could be anything from changing account settings to initiating financial transactions.
How a CSRF Attack Works
Here's how a CSRF attack might work:
- The victim logs into a web application, such as a bank site, which stores authentication cookies on the victim's browser.
- The attacker creates a malicious link or embeds code on another website that is designed to perform a specific action on the authenticated web application.
- If the victim visits the attacker's site or a site with the embedded code, the malicious action is triggered. Since the victim's browser still contains the authentication cookies, the web application considers the request legitimate.
- The targeted web application processes the request as if it were a legitimate user request. This could lead to unauthorized changes or actions performed without the user's consent.
- The victim may not even realize the attack has occurred, as they did not directly initiate the action.
A CSRF attack takes advantage of authenticated sessions, tricking a user's browser into performing actions without their knowledge or consent.
CSRF Tokens
To resolve these issues, we can add CSRF tokens to our forms. CSRF tokens, or anti-CSRF tokens, are a security measure used to prevent Cross-Site Request Forgery (CSRF) attacks. They work by ensuring that a submitted request is only accepted by a web application if it contains a unique, secret token that the server expects.
Here's how CSRF tokens work:
- When a user logs into a web application, the server generates a unique token. This token is tied to the user's session and embedded in the forms of the web application.
- The token is transmitted to the user's browser and stored either in a hidden form field or as a cookie.
- When the user submits a form or makes a request that requires authentication, the CSRF token is included as part of the request.
- Upon receiving the request, the server checks that the token in the request matches the token that was originally generated for that particular session. If the tokens match, the request is processed. If they don't, the request is rejected.
An attacker attempting to forge a request to the web application would not have access to the CSRF token, as it's unique to the user's session and known only to the server and the authenticated user's browser. Thus, the server would reject any unauthorized requests.
CSRF tokens add an additional layer of security, ensuring that a request is only accepted if it contains a unique identifier that is known only to the server and the authenticated user. This prevents attackers from tricking users into performing actions on a web application without their consent, as they would not have access to this unique identifier.
Generating a Token
In most cases, you should use a library for generating and validating tokens. However, it's completely possible to come up with your own solution for small to medium-sized applications.
As mentioned above, the first step is to create a token. You can create a CSRF token by generating a random string and storing it in the user's session. Below is an example of how you might create and manage a CSRF token.
// Enabling sessions are required for storing and persisting a token.
session_start();
// Grab HTTP Method
$method = strtoupper($_SERVER['REQUEST_METHOD']);
if ($method === "GET") {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
} else if ($method === "POST") {
// Process request
}
In the above code snippet, we're doing a few things.
- Enabling sessions.
- Grabbing the HTTP method. If the HTTP method is GET, we can proceed to generate a token. POST methods will cause the form to be processed.
- If the
$_SESSION['csrf_token']
variable is empty, we're setting it to therandom_bytes(32)
function to generate a random value. Tokens must always be unique and random.. We're also using thebin2hex()
function to convert the value into a human-readable string.
After generating a token, we must embed it into a form as a hidden field.
<form action="process.php" method="post">
<input
type="hidden"
name="csrf_token"
value="<?php echo $_SESSION['csrf_token']; ?>"
/>
<!-- rest of your form fields -->
<input type="submit" value="Submit" />
</form>
Validating a Token
On the server side, when processing the form submission, you should validate that the submitted token matches the one in the user's session.
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
// Token does not match; possible CSRF attack
die('Invalid CSRF token.');
} else {
// Token matches; process the form data
}
In the above example, we're comparing the value in the input field with the value stored in our session. If these values match, the token is valid. Otherwise, we stop the request from happening.
Here's the entire file:
<?php
// Enabling sessions are required for storing and persisting a token.
session_start();
// Grab HTTP Method
$method = strtoupper($_SERVER['REQUEST_METHOD']);
if ($method === "GET") {
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
} else if ($method === "POST") {
// Process request
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
// Token does not match; possible CSRF attack
die('Invalid CSRF token.');
} else {
// Token matches; process the form data
}
}
?>
<form action="process.php" method="post">
<input
type="hidden"
name="csrf_token"
value="<?php echo $_SESSION['csrf_token']; ?>"
/>
<!-- rest of your form fields -->
<input type="submit" value="Submit" />
</form>
Key Takeaways
- CSRF is an attack where an attacker tricks a user into performing unwanted actions on an authenticated web application. Awareness of this threat is the first step toward protection.
- CSRF tokens are unique, secret identifiers used to validate requests, ensuring they come from authenticated and authorized users.
- Tokens should be randomly generated using strong cryptographic functions like
random_bytes()
in PHP and tied to the user's session. - Tokens are embedded in hidden fields within forms, and they are sent along with form submissions to the server for validation.
- On the server side, tokens from the request must be compared to the tokens stored in the user's session to verify their authenticity.