AWS WAF and CSRF Rule

Shouki Souri
7 min readJan 27, 2020

--

The What, Why and How…

A simple AWS Architecture with AWS WAF at work

AWS WAF stands for a Web Application Firewall that helps protect your web applications or APIs against common web exploits that may affect availability, compromise security, or consume excessive resources. The pricing is based on how many rules you deploy and how many web requests your application receives. WAF integrates well with Amazon CloudFront, EC2, API Gateway, and Application Load Balancer.

Note: AWS has recently introduced a new AWS WAF in November 2019, featuring a new AWS WAFV2 API, an improved console, and AWS Managed Rules. The previous version of AWS WAF is now named AWS WAF Classic. Unfortunately, resources created under AWS WAF Classic are not compatible with the new AWS WAF console or API. If you created AWS WAF resources, like rules and web ACLs, prior to November 2019, you either need to use AWS WAF Classic to work with those resources (I decided to stick with WAF classic at least for now), or you need to migrate them to the latest version. The migration is a manual process. Click on the link for more information or tips on migrating your AWS WAF Classic resources to the new AWS WAF.

If your web application does not contain sensitive information (such as SSN, PII, HIPAA, Credit Card information, etc.), you can decide to deploy fewer rules and pay less. However, If your web application deals with sensitive information, then it is strongly recommended to deploy more rules for enhanced and added security.

For a list of top common categories of application security flaws, I used the Open Web Application Security Project (OWASP)’s top 10 Web Application Vulnerabilities. AWS has published a whitepaper on how to use AWS WAF to Mitigate OWASP’s Top 10 Web Application Vulnerabilities. The whitepaper provides background and context for each vulnerability and then shows you how to create WAF rules to identify and block them. By inspecting HTTP traffic, it can block attacks coming from web application security flaws, such as SQL injection, broken authentication and session management, cross-site scripting (XSS), Cross-Site Request Forgery (CSRF), and security misconfigurations.

CSRF listed as A8 on the top 10 (based on OWASP 2017)

Using the AWS CloudFromation template “owasp_10_base.yml” from the GitHub repository — waf-owasp-top-10 that contains AWS WAF web access control list (ACL) and condition types and rules to generate these rules in WAF. Please read the usage license and note that this template is designed only as a starting point and may not provide sufficient protection to every workload. You should customize the template’s rules for each workload.

Using CloudFormation Designer, the template creates all the resources the script configure for us

In this article, however, we are only going to focus on Cross-Site Request Forgery (CSRF) rule and what implementation methods the developer has to use to mitigate these attacks.

First thing first, What is CSRF anyway?

OWASP CSRF definition:

CSRF is a type of attack that occurs when a malicious web site, email, blog, instant message, or program causes a user’s web browser to perform an unwanted action on a trusted site for which the user is currently authenticated. The impact of a successful CSRF attack is limited to the capabilities exposed by the vulnerable application. For example, this attack could result in a transfer of funds, changing a password, or purchasing an item in the user’s context. In effect, CSRF attacks are used by an attacker to make a target system perform a function via the target’s browser without knowledge of the target user, at least until the unauthorized transaction has been committed.

Essentially, the attack is piggy-backing off of the user’s valid session that is stored in their cookies, using that as a way to access to an authenticated victim’s bank account as an example.

The Details:

The “Use AWS WAF to Mitigate OWASP’s Top 10 Web Application Vulnerabilities” whitepaper presents three implementation methods to mitigate CSRF attacks (page 20):

  1. Including unpredictable tokens in the HTTP request that triggers the
    action.
  2. Prompting users to authenticate for sending action requests.
  3. Introducing CAPTCHA challenges for sending action requests.

The first method is the only method that is transparent and frictionless to the end-users and more importantly considered more secure than the other two methods.

This method is to include unpredictable tokens in the HTTP request — forms can include unique tokens as hidden form fields, that triggers the action.

You can use AWS WAF to check for the presence of those unique tokens. For example, if you decide to leverage a random universally unique identifier (UUIDv4) as the CSRF token, and expect the value in a custom HTTP header named x-csrf-token, you can implement a size constraint condition.

This is saying that when making use of a Custom header, then WAF can be used to verify its size. Do note that WAF does not validate the token it only makes sure that it is in the header. The backend EC2 instance(s) needs to still validate the token/request in the field and/or header.

A sample PHP test code demonstrates how an application generates a random UUIDv4 as the CSRF token and how it is validated.

<?php 
error_reporting(E_ALL);
ini_set('display_errors', 1);
session_start();
$digits = 4;
function gen_uuid() {
return sprintf( '%04x%04x%04x%04x%04x%04x%04x%04x',
// 32 bits for "time_low"
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
// 16 bits for "time_mid"
mt_rand( 0, 0xffff ),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand( 0, 0x0fff ) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand( 0, 0x3fff ) | 0x8000,
// 48 bits for "node"
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
);
}
$new_token = gen_uuid() . str_pad(rand(0, pow(10, $digits)-1), $digits, '0', STR_PAD_LEFT);
if (!isset($_SESSION['token']))
{
$_SESSION['token'] = $new_token;
echo "token:" . $_SESSION['token'];
$token = $_SESSION['token'];
header("x-csrf-token: " . $token);
}
?>
<html>
<body>
<h5>x-csrf-token in header: <?php echo $_SESSION['token']; ?></h5>
<?php if (!isset($_POST["token"])) { ?>
<form id="test_form" action="#" enctype="multipart/form-data">
Input: <input type="text" name="FormInput" id="FormInput">
<br /><br />
Token: <input type="text" name="FormToken" id="FormToken" value="<?php echo $_SESSION['token']; ?>" size="45">
<input type="button" value="Test" onclick="send_request();" />
</form>
<h1>Validation:</h1>
<div id="response">
<?php } else {
if ($_SESSION['token'] == $_POST['token']) {
echo "<h3>Post Request:</h3>";
print_r($_POST);
echo "<h3>Headers received:</h3>";
foreach (getallheaders() as $name => $value) {
echo "$name: $value\n";
}
} else {
echo "<br>Invalid<br>";
}
}?>
</div>
</body>
<script>
send_request = function() {
var xhttp = new XMLHttpRequest();
var FormInput = document.getElementById("FormInput").value;
var FormToken = document.getElementById("FormToken").value;
xhttp.open("POST", "<?php echo $_SERVER['PHP_SELF']; ?>", false);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.setRequestHeader("x-csrf-token", FormToken);
xhttp.send("FormInput="+FormInput+"&token="+FormToken);
document.getElementById("response").innerHTML = xhttp.responseText;
};
</script>
</html>

After launching our CloudFormation stack from the template, two CSRF rules as shown below are generated. As I indicated before, you have the option to edit to the rules based on the mitigation options that you prefer to take.

The rules below state that if the request HTTP method MATCHES the two conditions (see “AND” logic), then WAF “Block” the request (403 ERROR), otherwise “Allow” the request based on the web ACL selection shown below. Note: A third action called “Count” is listed and its purpose is to allow you to count the number of web requests that are matched by the rules inside the Managed Rule. You can look at the number of counted web requests to estimate how many of your web requests would be blocked if you enable the Managed Rule. This is very handy for testing purposes before committing to either blocking or allowing action.

The logic table below (T = True/Match, F = False/No Match) created to simplify the logic what would be the output from these rules:

As you see from the table that the WAF will only block HTTP request that is a “post” request AND the length of the header x-csrf-token does not equal 36 (bytes/ASCII characters, canonical format), all others are allowed through by the WAF.

As new vulnerabilities arise, AWS WAF can adapt and look for unusual traffic flows and new rules can be deployed as part of your application security framework in the Cloud.

Related References

  1. Open Web Application Security Project (OWASP)
  2. Cross-Site Request Forgery (CSRF)
  3. AWS WAF
  4. Use AWS WAF to Mitigate OWASP’s Top 10 Web Application Vulnerabilities
  5. AWS CloudFromation template “owasp_10_base.yml

--

--