CSRF protection
Testomato & CSRF protection
Can Testomato handle forms with CSRF protection? The simply answer is NO. If your application is protected from cross-site request forgery attacks, it's also preventing Testomato from sending requests with minicrawler, but we can try to bridge the simplest type of protection by doubling the request.
- During the first request, Testomato ignores HTTP response code - usually there’s some sort of unauthorized request response, but we update all hidden form params values and save the session.
- The second request is submitted within the same session in the hopes that one of the hidden params has a valid CSRF token
What is CSRF protection
Cross-site request forgeries are a type of malicious exploit where unauthorized commands are performed on behalf of an authenticated user.
In case you're not familiar with cross-site request forgeries, let's discuss an example of how this vulnerability can be exploited.
Imagine your application has a /user/email route that accepts a
POST request to change the authenticated user's email address. This route most likely expects
an email input field to contain the email address the user would like to begin using.
Without CSRF protection, a malicious website could create an HTML form that points to your
application's /user/email route and submits the malicious user's own email address
<form action="https://your-application.com/user/email" method="POST">
<input type="email" value="malicious-email@example.com">
</form>
<script>
document.forms[0].submit();
</script>
Preventing CSRF Requests
You can generate a CSRF "token" for each active user session managed by the application. This token is used to verify that the authenticated user is the person actually making the requests to the application. Since this token is stored in the user's session and changes each time the session is regenerated, a malicious application is unable to access it.
<?php
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['token'];
?>
<form action="https://your-application.com/user/email" method="POST">
<input type="email" value="malicious-email@example.com">
<input type="hidden" name="token" value="<?php echo $token ?>" />
</form>
Anytime you define an HTML form in your application,
you should include a hidden CSRF _token field in the
form so that the CSRF protection can validate the request.
if (!empty($_POST['token'])) {
if (hash_equals($_SESSION['token'], $_POST['token'])) {
// Proceed to process the form data
} else {
// Log this as a warning and keep an eye on these attempts
}
}
Per-Form Tokens
You can go even further and generate Per-Form Tokens for every single form on your application:
<?php $second_token = hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']); ?>
<input type="hidden" name="token" value="<?php echo $second_token ?>" />
<?php
$calc = hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
if (hash_equals($calc, $_POST['token'])) {
// Continue...
}
You can also change the name of the token variable or invalidate a token periodically in time. If you have a security requirement that each CSRF token is allowed to be usable exactly once, the simplest strategy is to regenerate it after each successful validation. However, doing so will invalidate every previous token, which can negatively impact the experience of users who browse multiple tabs simultaneously.