AWS WAF レートベースルールを用いた DDoS 攻撃の緩和

AWS WAF レートベースルールを用いた DDoS 攻撃の緩和

岩佐 孝浩
岩佐 孝浩
6 min read
WAF

はじめに

AWS WAF は、SQL インジェクションや XSS といった レイヤー 7 攻撃 からの保護を提供します。また、レートベースルール を使用することで DDoS 攻撃の緩和 も可能です。このルールでは、各 IP アドレスからの HTTP リクエストに対して閾値を設定できます。本記事では、その効果的な使用方法について説明します。

概要

以下の主要なポイントについてご確認ください。

  • 最小レートは 100 に設定できます。 1
  • AWS WAF はリクエストのレートを 30 秒ごとに確認し、毎回直近 5 分間のリクエストをカウントします。そのため、集約インスタンスが高いレートのリクエストを受信しても、AWS WAF が検出して制限するまでに最大で 30 秒かかる場合があります。 2
  • 単一のレートベースルールインスタンスで AWS WAF がレート制限できる IP アドレスの最大数は 10,000 です。10,000 を超えるアドレスがレートを超えた場合、AWS WAF は最も高いレートのものを制限します。 3

AWS リソースの作成

以下の CloudFormation テンプレートを使用して必要なリソースを作成できます。主要な設定は Limit および AggregateKeyType(53-54 行目)です。この例では、レート制限を 100 に設定しています。

AWSTemplateFormatVersion: 2010-09-09
Description: AWS WAF Rate-based rule sample
Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub aws-waf-rate-based-rule-sample-${AWS::AccountId}-${AWS::Region}
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: TRUE
        BlockPublicPolicy: TRUE
        IgnorePublicAcls: TRUE
        RestrictPublicBuckets: TRUE

  S3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3Bucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: cloudfront.amazonaws.com
            Action: s3:GetObject
            Resource: !Sub arn:aws:s3:::${S3Bucket}/*
            Condition:
              StringEquals:
                "AWS:SourceArn": !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}

  # AWS::WAFv2::WebACL must be deployed in us-east-1.
  WAFv2WebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: aws-waf-rate-based-rule-sample
      DefaultAction:
        Allow: { }
      VisibilityConfig:
        SampledRequestsEnabled: true
        CloudWatchMetricsEnabled: true
        MetricName: aws-waf-rate-based-rule-sample
      Scope: CLOUDFRONT
      Rules:
        - Name: rate-based-rule
          Priority: 0
          Action:
            Block: { }
          Statement:
            RateBasedStatement:
              Limit: 100
              AggregateKeyType: IP
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: rate-based-rule

  CloudFrontOriginAccessControl:
    Type: AWS::CloudFront::OriginAccessControl
    Properties:
      OriginAccessControlConfig:
        Name: aws-waf-rate-based-rule-sample
        OriginAccessControlOriginType: s3
        SigningBehavior: always
        SigningProtocol: sigv4

  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    DependsOn: CloudFrontOriginAccessControl
    Properties:
      DistributionConfig:
        Origins:
          - Id: !GetAtt S3Bucket.DomainName
            DomainName: !GetAtt S3Bucket.DomainName
            OriginAccessControlId: !Ref CloudFrontOriginAccessControl
            S3OriginConfig:
              OriginAccessIdentity: ''
        DefaultCacheBehavior:
          CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
          TargetOriginId: !GetAtt S3Bucket.DomainName
          ViewerProtocolPolicy: allow-all
        Enabled: true
        ViewerCertificate:
          CloudFrontDefaultCertificate: true
          MinimumProtocolVersion: TLSv1
        WebACLId: !GetAtt WAFv2WebACL.Arn
        DefaultRootObject: index.html

デプロイ手順

1. CloudFormation スタックをデプロイする

aws cloudformation deploy \
  --region us-east-1 \
  --stack-name aws-waf-rate-based-rule-sample \
  --template-file template.yaml

2. S3 バケットにサンプルの index.html をアップロードする

echo '<html><body>Hello World!</body></html>' > index.html
aws s3 cp index.html s3://aws-waf-rate-based-rule-sample-<ACCOUNT_ID>-us-east-1

テスト

AWS WAF のレートチェック間隔は 30 秒です。そのため、1 秒ごとに 130 秒以上リクエストを送信してテストを行います。設定された制限を超えたリクエストは、403 Forbidden レスポンスによってブロックされます。

AWS WAF checks the rate of requests every 30 seconds, and counts requests for the prior five minutes each time.

for i in `seq 1 130`; do
  echo "Request: $i"
  curl https://<CLOUDFRONT_DOMAIN>/
  echo "\n"
  sleep 1
done

ブロックされたレスポンスの例:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>403 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Request blocked.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: xxxxxxxxxxxxxxxxxxxx
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>

クリーンアップ

テスト後、以下のコマンドで AWS リソースをクリーンアップしてください。

aws s3 rm --recursive s3://aws-waf-rate-based-rule-sample-<ACCOUNT_ID>-us-east-1
aws cloudformation delete-stack \
  --region us-east-1 \
  --stack-name aws-waf-rate-based-rule-sample

まとめ

AWS WAF の レートベースルール を活用することで、DDoS 攻撃をある程度緩和することができます。ただし、より完全な保護のためには、このアプローチを AWS Shield Advanced などの追加ソリューションと組み合わせることをお勧めします。

本記事が、潜在的な脅威からアプリケーションを保護する一助となれば幸いです。

Happy Coding! 🚀


Footnotes

  1. Rate-based rule high-level settings in AWS WAF

  2. Applying rate limiting to requests in AWS WAF

  3. Listing IP addresses that are being rate limited by rate-based rules

岩佐 孝浩

岩佐 孝浩

Software Developer at KAKEHASHI Inc.
AWS を活用したクラウドネイティブ・アプリケーションの要件定義・設計・開発に従事。 株式会社カケハシで、処方箋データ収集の新たな基盤の構築に携わっています。 Japan AWS Top Engineers 2020-2023