AWS-WAF

AWS WAFでJA3 フィンガープリント照合による遮断設定を入れてみた

はじめに

こんにちは、ディーネットの山田です。

すっかりニュースでは聞かなくなったコロナウイルスに、つい最近はじめて感染して高熱に促されておりました。

皆さんも健康にはお気を付けください。

さて、話は本題に戻りますが、JA3 フィンガープリントを用いてAWS WAF上で遮断する設定を検証する機会がありましたので、設定方法をご紹介したいと思います。

JA3 フィンガープリントについて

TLS Client Helloパケットで交わされる、TLS バージョン、受け入れられた暗号、拡張子のリスト、サポートされているグループ、および楕円曲線形式に基づいて計算されたMD5のハッシュ値になります。

Open Sourcing JA3
TLS Fingerprinting with JA3 and JA3S

詳しい技術情報としては、GitHubで公開されております。

JA3 gathers the decimal values of the bytes for the following fields in the Client Hello packet; SSL Version, Accepted Ciphers, List of Extensions, Elliptic Curves, and Elliptic Curve Formats. It then concatenates those values together in order, using a "," to delimit each field and a "-" to delimit each value in each field.

以下、ヘッダーの情報に基づいてMD5のハッシュ値が計算されるようです。

SSLVersion,Cipher,SSLExtension,EllipticCurve,EllipticCurvePointFormat

JA3 - A method for profiling SSL/TLS Clients

環境の構成図

AWS環境の構成としては、Amazon CloudFrontにAWS WAFを連携する形で、WAFを利用するように作成しました。
EC2を1台設置してインターネット上のクライアントPCとはWAFが連携されたAmazon CloudFrontを経由してWebページを配信するようにしました。

構成要素

  • AWS WAF
    • Amazon CloudFrontを経由するSSL/TLS通信のJA3 フィンガープリントをチェックして合致するものがあれば遮断する目的で使用します。

実際に設定していきます

前提としては、以下を仮定しております。

  • AWS WAFを使った環境は、既に構築済み。
  • WAFルールは、手動で運用もしくは自動運用のルールと競合しない。
  • 遮断したいJA3フィンガープリントの値は調査済み。

JA3フィンガープリントを使ったWAFのルールを作成する

  • 「Add my own rules and rule groups」をクリックする

  • RuleのNameには、任意の名前を入力する

  • JA3フィンガープリントに基づく条件を作成する
    • 「Inspect」に「JA3 fingerprint」を選択
    • 「String to match」に遮断したいJA3フィンガープリントの値を入力
      • 以下の例では、CentOS7.9のcurlが使用するJA3フィンガープリントを入力しております
    • 「Fallback for missing JA3 fingerprint」については、「No match」を選択
      • 「Match」・・・JA3フィンガープリントをAWS WAFが計算できなかった場合にマッチする
      • 「No match」・・・JA3フィンガープリントをAWS WAFが計算できなかった場合はマッチしない

  • 条件に合致した際の挙動について設定する

  • 複数のルールが存在する場合は、優先順位を選択する

  • JSONでルールを出力すると以下になります。
{
  "Name": "DENET_TEST_JA3_BLOCK_RULE",
  "Priority": 0,
  "Statement": {
    "ByteMatchStatement": {
      "SearchString": "c8446f59cca2149cb5f56ced4b448c8d",
      "FieldToMatch": {
        "JA3Fingerprint": {
          "FallbackBehavior": "NO_MATCH"
        }
      },
      "TextTransformations": [
        {
          "Priority": 0,
          "Type": "NONE"
        }
      ],
      "PositionalConstraint": "EXACTLY"
    }
  },
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "DENET_TEST_JA3_BLOCK_RULE"
  }
}

先ほどの遮断設定を有効化して動作検証してみた

  • WAFによる遮断前

    $ curl -v -s -o /dev/null https://denet.example.com/
    * About to connect() to denet.example.com port 443 (#0)
    *   Trying 18.65.159.81...
    * Connected to denet.example.com (18.65.159.81) port 443 (#0)
    * Initializing NSS with certpath: sql:/etc/pki/nssdb
    *   CAfile: /etc/pki/tls/certs/ca-bundle.crt
      CApath: none
    * SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    * Server certificate:
    *       subject: CN=denet.example.com
    *       start date:  2月 26 00:00:00 2024 GMT
    *       expire date:  3月 27 23:59:59 2025 GMT
    *       common name: denet.example.com
    *       issuer: CN=Amazon RSA 2048 M03,O=Amazon,C=US
    > GET / HTTP/1.1
    > User-Agent: curl/7.29.0
    > Host: denet.example.com
    > Accept: */*
    > 
    < HTTP/1.1 200 OK
    < Content-Type: text/html; charset=UTF-8
    < Transfer-Encoding: chunked
    < Connection: keep-alive
    < Date: Mon, 08 Apr 2024 07:04:55 GMT
    < Server: Apache
    < X-Powered-By: PHP/7.4.33
    < Link: ; rel="https://api.w.org/", ; rel="alternate"; type="application/json", ; rel=shortlink
    < X-Cache: Miss from cloudfront
    < Via: 1.1 95ba818b4f15305758db1a15f06338e0.cloudfront.net (CloudFront)
    < X-Amz-Cf-Pop: NRT51-P2
    < X-Amz-Cf-Id: IyY0f7UDIjayGAR9IKgC0MKs6v8kHBIjHBeoyCJZ4ddziSg27ef-6w==
    < 
    { [data not shown]
    * Connection #0 to host denet.example.com left intact
  • WAFによる遮断後

    $ curl -v -s -o /dev/null https://denet.example.com/
    * About to connect() to denet.example.com port 443 (#0)
    *   Trying 18.65.159.29...
    * Connected to denet.example.com (18.65.159.29) port 443 (#0)
    * Initializing NSS with certpath: sql:/etc/pki/nssdb
    *   CAfile: /etc/pki/tls/certs/ca-bundle.crt
      CApath: none
    * SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    * Server certificate:
    *       subject: CN=denet.example.com
    *       start date:  2月 26 00:00:00 2024 GMT
    *       expire date:  3月 27 23:59:59 2025 GMT
    *       common name: denet.example.com
    *       issuer: CN=Amazon RSA 2048 M03,O=Amazon,C=US
    > GET / HTTP/1.1
    > User-Agent: curl/7.29.0
    > Host: denet.example.com
    > Accept: */*
    > 
    < HTTP/1.1 403 Forbidden
    < Server: CloudFront
    < Date: Mon, 08 Apr 2024 07:19:54 GMT
    < Content-Type: text/html
    < Content-Length: 919
    < Connection: keep-alive
    < X-Cache: Error from cloudfront
    < Via: 1.1 4edb41b4327528fd68cb3f0568bebe58.cloudfront.net (CloudFront)
    < X-Amz-Cf-Pop: NRT51-P2
    < X-Amz-Cf-Id: LI81cMmYcbE567xf-B6KIFkx8r3lmPRIwkkEHE0-mLf2W7snzCwVFA==
    < 
    { [data not shown]
    * Connection #0 to host denet.example.com left intact
  • OSのバージョンが異なる別環境は問題なくアクセス可能だった

$ curl -v -s -o /dev/null https://denet.example.com/
* About to connect() to denet.example.com port 443 (#0)
*   Trying 18.65.159.92...
* Connected to denet.example.com (18.65.159.92) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
*       subject: CN=denet.example.com
*       start date:  2月 26 00:00:00 2024 GMT
*       expire date:  3月 27 23:59:59 2025 GMT
*       common name: denet.example.com
*       issuer: CN=Amazon RSA 2048 M03,O=Amazon,C=US
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: denet.example.com
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Date: Mon, 08 Apr 2024 07:38:05 GMT
< Server: Apache
< X-Powered-By: PHP/7.4.33
< Link: <https://denet.example.com/wp-json/>; rel="https://api.w.org/", <https://denet.example.com/wp-json/wp/v2/pages/12>; rel="alternate"; type="application/json", <https://denet.example.com/>; rel=shortlink
< X-Cache: Miss from cloudfront
< Via: 1.1 e49ce0f79e9d31dbaa961dc49bb7b27c.cloudfront.net (CloudFront)
< X-Amz-Cf-Pop: NRT51-P2
< X-Amz-Cf-Id: cTjhUKF_JmK1DnyUCTZMxW4NGHeYjYQPqQn0taVuS554b39twMjlmA==
< 
{ [data not shown]
* Connection #0 to host denet.example.com left intact

備考

  • JA3フィンガープリントの値ですが、TLS Client Helloランダム順列機能を使われると、一意の値ではなくなるため本対応による遮断設定の効果は薄くなります。

参考サイト

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA