AWS WAF のレートベースルールで DDoS を緩和する

AWS WAF のレートベースルールで DDoS を緩和する

AWS WAF のレートベースルールで過剰なリクエストを制限し、アプリケーションレイヤーの DDoS 攻撃を緩和します。

Takahiro Iwasa
5 min read

AWS WAF は、SQL インジェクションやクロスサイトスクリプティング(XSS)などのレイヤー 7 攻撃から Web アプリケーションを保護します。レートベースルールを使うと、過剰なリクエストを制限し、アプリケーションレイヤーの DDoS 攻撃を緩和できます。

🔥 Caution

AWS WAF のレートベースルールは DDoS 攻撃の緩和に役立ちますが、完全な保護を提供するものではありません。より包括的な保護が必要な場合は、AWS Shield Advanced の利用を検討してください。

2023 年 1 月時点の動作と制限は、次のとおりです。

  • 設定できる最小レートは、追跡対象の IP アドレスごとに5 分間で 100 リクエストです。
  • AWS WAF は30 秒ごとにリクエストレートを確認し、その都度直近 5 分間のリクエストを集計します。そのため、トラフィックを検知して制限するまでに最大 30 秒かかる場合があります。
  • AWS WAF のレート制限で追跡できる IP アドレスは 10,000 個までです。10,000 個を超えるアドレスがレートを超過した場合、リクエストレートが最も高いものから制限します。

構築

以下のテンプレートでは、送信元 IP アドレスごとに5 分間で 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

スタックをデプロイします。

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

Scope: CLOUDFRONT を含む AWS WAFv2 Web ACL ルールは、us-east-1 リージョンにデプロイする必要があります。

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

Terminal window
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 秒に 1 回のリクエストを 130 秒以上送信します。設定した上限を超えた状態が評価されると、以後のリクエストは 403 Forbidden レスポンスでブロックされます。

https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-rate-based.html

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

Terminal window
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>

クリーンアップ

この例でプロビジョニングしたリソースを以下のコマンドで削除します。

Terminal window
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

まとめ

送信元 IP アドレスが 5 分間で 100 リクエストという上限を超えると、WAF のレートベースルールが CloudFront ディストリビューションへのリクエストを 403 レスポンスでブロックします。

テスト時に注意したいのが、30 秒の評価間隔です。直近 5 分間のリクエスト数が上限を超えた後も、AWS WAF が次に評価するまではリクエストが通過する場合があります。

評価の遅延と 10,000 IP という追跡上限があるため、これは完全な DDoS 防御ではなく緩和策です。レートベースルールは AWS Shield Advanced などを補完するものであり、その代替にはなりません。

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

This blog shares technical notes from hands-on projects—architecture, implementation, and AWS service integrations.