Waf Charm

Blog

AWS WAF now supports inspection with JA3 fingerprints

Table of Contents

  1. 1. Introduction
  2. 2. What is JA3 fingerprint?
  3. 3. Setting up the rule
  4. 4. Testing the rule
  5. 5. Effects on WafCharm
  6. 6. Conclusion

1. Introduction

AWS WAF announced that it now supports inspection of JA3 fingerprints on September 27th, 2023.
AWS WAF now supports JA3 Fingerprint Match

In this blog post, we will take a look at the update.

2. What is JA3 fingerprint?

JA3 fingerprint is a 32-character MD5 hash derived from the values in request's TLS Client Hello such as TLS version and Cipher Suites.
GitHub - salesforce/ja3: JA3 is a standard for creating SSL client fingerprints in an easy to produce and shareable way.

If AWS WAF is able to calculate the fingerprint, the value will be available under the "ja3Fingerprint" field in WAF logs.
For more information on AWS WAF's JA3 fingerprints, please refer to the document below.
Request component options - AWS WAF, AWS Firewall Manager, and AWS Shield Advanced

3. Setting up the rule

You can create a rule to inspect the JA3 fingerprint with the steps shown below.

1. Click the [Add rules] button on the right side of the Web ACLs page and click [Add my own rules and rule groups].

2. Enter the rule name.

3. Select [JA3 fingerprint] under the [Inspect] in the [Statement].

4. Enter the value you want to match in [String to match].

Match type will be [Exactly matches string] for JA3 fingerprint, and this option cannot be changed.

5. Select the option from [Match] or [No match] under the [Fallback for missing JA3 fingerprint].

This fallback behavior determines what to do with the request if AWS WAF can't calculate the JA3 fingerprint.
If you choose Match, the request will be treated as matching the rule, and rule action will be applied.
If you choose No match, then the request will not match the rule.

6. Select the rule action and click [Add rule].

4. Testing the rule

First, we will obtain the JA3 fingerprint value to test the rule.

We will access the target website like we normally do because the fingerprint will be included in the WAF log if AWS WAF can calculate the value.
When we checked the WAF log, we could see that the fingerprint was available as shown below.

"ja3Fingerprint": "JA3 fingerprint value"

We've masked the actual value, but let's add a rule to block the request with the fingerprint provided in the WAF log.
For the testing, fallback behavior will be [No match].

{
  "Name": "ja3-fingerprint-test",
  "Priority": 0,
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "ja3-fingerprint-test"
  },
  "Statement": {
    "ByteMatchStatement": {
      "FieldToMatch": {
        "JA3Fingerprint": {
          "FallbackBehavior": "NO_MATCH"
        }
      },
      "PositionalConstraint": "EXACTLY",
      "SearchString": "JA3 fingerprint value",
      "TextTransformations": [
        {
          "Type": "NONE",
          "Priority": 0
        }
      ]
    }
  }
}

When we've accessed the website after adding the rule, we could see the 403 error page and the request was blocked.

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
</body>
</html>

We can also see that the request was blocked with the JA3 fingerprint rule from the WAF log below.

{
    "timestamp": 1696395560834,
    "formatVersion": 1,
    "webaclId": "Web ACL's ARN",
    "terminatingRuleId": "ja3-fingerprint-test",
    "terminatingRuleType": "REGULAR",
    "action": "BLOCK",
    "terminatingRuleMatchDetails": [],
    "httpSourceName": "ALB",
    "httpSourceId": "Associated resource ID",
    "ruleGroupList": [],
    "rateBasedRuleList": [],
    "nonTerminatingMatchingRules": [],
    "requestHeadersInserted": null,
    "responseCodeSent": null,
    "httpRequest": {
        "clientIp": "IP address",
        "country": "JP",
        "headers": [
            {
                "name": "host",
                "value": "Host value"
            },
            {
                "name": "user-agent",
                "value": "curl/7.86.0"
            },
            {
                "name": "accept",
                "value": "*/*"
            }
        ],
        "uri": "/",
        "args": "",
        "httpVersion": "HTTP/2.0",
        "httpMethod": "GET",
        "requestId": "Request ID"
    },
    "ja3Fingerprint": "JA3 fingeprint value"
}

When we tested using Google Chrome, some of the requests couldn't be blocked because Chrome has a feature to randomize the JA3 fingerprint for each connection.

It seems like the requests sent in a short period of time had the same JA3 fingerprints from what we can see in the WAF logs, but when the requests were distributed over some time, JA3 fingerprints had different values and didn't match the rule.

5. Effects on WafCharm

You can apply rules to inspect JA3 fingerprint on web ACLs that uses WafCharm.

We can also provide customization service for WafCharm users.
If you want to apply customized rule, please contact the WafCharm support team.

6. Conclusion

JA3 fingerprint might be fixed depending on the client.
IP addresses and domains are easy to change, but if the fingerprint is a fixed value, you can use the JA3 fingerprint to block the requests.

However, some clients like Chrome may have a feature to randomize JA3 fingerprints. We recommend you to recognize that rules that inspect JA3 fingerprint may not be enough to protect against threats in such cases.