AWS WAFのSQLインジェクション防御機能
AWS WAF(Web Application Firewall)は、AWSのマネージドサービスとして提供される、クラウドネイティブなWebアプリケーション防御ソリューションです。特にSQLインジェクション対策において、高度な検知機能と柔軟なルール設定により、効果的な防御を実現します。
Core Rule Set(CRS)の概要
AWS WAFの中核となるCore Rule Set(CRS)は、OWASP Top 10に対応した包括的なルールセットです。SQLインジェクション対策として、複数の検知レイヤーを提供します。
SQLインジェクション検知ルール
CRSには、SQLインジェクションを検知するための階層的なルールが含まれています。
| ルールID | 検知内容 | 感度レベル | 誤検知率 | 推奨用途 |
|---|---|---|---|---|
| 942100 | SQLキーワード検出(SELECT、UNION等) | 1-4 | 低 | 基本防御 |
| 942200 | SQL演算子検出(OR、AND、=等) | 1-4 | 中 | 標準防御 |
| 942300 | SQL関数検出(CONCAT、SLEEP等) | 2-4 | 中 | 高度な攻撃対策 |
| 942400 | チェーンSQL検出(複合的な攻撃) | 3-4 | 高 | 複雑な攻撃対策 |
| 942500 | MySQL特有の攻撃パターン | 2-4 | 低 | MySQL環境 |
| 942600 | PostgreSQL特有の攻撃パターン | 2-4 | 低 | PostgreSQL環境 |
感度レベルは1(最も緩い)から4(最も厳しい)まで設定可能で、ビジネス要件に応じて調整できます。
Managed Rulesの選択と設定
AWS WAFでは、AWSが管理・更新するマネージドルールを利用することで、専門知識なしに高度な防御を実現できます。
- AWS Managed Rules for SQL Database
- SQLインジェクション対策に特化したルールセットです。月額$20から利用可能で、データベース種別(MySQL、PostgreSQL、SQL Server、Oracle)に応じた最適化されたルールが含まれています。定期的な更新により、新しい攻撃パターンにも自動対応します。誤検知を最小化するため、機械学習により継続的に改善されています。
- 感度レベル設定
- Low(誤検知最小)は、ビジネスクリティカルなアプリケーション向けで、確実な攻撃のみをブロックします。Medium(バランス型)は、一般的なWebアプリケーションに推奨され、防御力と可用性のバランスを取ります。High(検知率最大)は、セキュリティを最優先する環境向けで、疑わしいリクエストも積極的にブロックします。
- 除外ルール設定
- 特定のルールIDを無効化することで、業務に影響する誤検知を削減できます。例えば、CMSの管理画面でHTMLエディタを使用する場合、特定のパスに対してSQL関数検出ルールを無効化するなど、きめ細かな調整が可能です。除外設定は、パス、クエリパラメータ、ヘッダー単位で指定できます。
カスタムルールによる強化
標準的なマネージドルールに加え、自社環境に特化したカスタムルールを作成することで、より精密な防御を実現できます。
{
"Name": "CustomSQLiProtection",
"Priority": 100,
"Statement": {
"OrStatement": {
"Statements": [
{
"SqliMatchStatement": {
"FieldToMatch": {
"QueryString": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "URL_DECODE"
},
{
"Priority": 1,
"Type": "HTML_ENTITY_DECODE"
},
{
"Priority": 2,
"Type": "LOWERCASE"
}
]
}
},
{
"SqliMatchStatement": {
"FieldToMatch": {
"Body": {
"OversizeHandling": "MATCH"
}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "BASE64_DECODE"
},
{
"Priority": 1,
"Type": "URL_DECODE"
}
]
}
},
{
"RegexMatchStatement": {
"RegexString": "(?i)(\\bUNION\\b.*\\bSELECT\\b|\\bOR\\b.*1\\s*=\\s*1|\\bAND\\b.*1\\s*=\\s*1)",
"FieldToMatch": {
"AllQueryArguments": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "URL_DECODE"
}
]
}
}
]
}
},
"Action": {
"Block": {
"CustomResponse": {
"ResponseCode": 403,
"CustomResponseBodyKey": "blocked-request",
"ResponseHeaders": [
{
"Name": "X-Block-Reason",
"Value": "SQL-Injection-Detected"
}
]
}
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "CustomSQLiProtection"
}
}
マネージドルールセットの選定と設定
適切なマネージドルールセットの選択は、効果的な防御と運用負荷軽減の鍵となります。
利用可能なルールセット一覧
AWS WAFで利用可能な主要ルールセットと、その特徴を理解することが重要です。
AWS提供のマネージドルール
# AWS Managed Rules 価格表(2025年版)
1. Core Rule Set (CRS)
料金構成:
- 基本料金: $5/月
- リクエスト料金: $1/百万リクエスト
- Web ACL: $5/月
特徴:
- OWASP Top 10完全対応
- SQLインジェクション基本検知
- XSS、コマンドインジェクション対応
- 誤検知率: 低
2. SQL Database Rule Set
料金構成:
- 基本料金: $20/月
- リクエスト料金: $0.60/百万リクエスト
特徴:
- SQL特化の詳細検知
- データベース種別対応
- ブラインドSQLi検知
- 時間ベース攻撃検知
3. Known Bad Inputs Rule Set
料金構成:
- 基本料金: $5/月
- リクエスト料金: $1/百万リクエスト
特徴:
- 既知の攻撃パターンDB
- 週次更新
- CVEデータベース連携
- 低誤検知率
4. PHP Application Rule Set
料金構成:
- 基本料金: $20/月
- リクエスト料金: $0.60/百万リクエスト
特徴:
- PHPアプリ特有の脆弱性対策
- LFI/RFI検知
- PHPインジェクション対策
5. Linux Operating System Rule Set
料金構成:
- 基本料金: $20/月
- リクエスト料金: $0.60/百万リクエスト
特徴:
- OSコマンドインジェクション対策
- パストラバーサル検知
- シェルショック対策
サードパーティ製ルール
AWS Marketplaceで提供される、セキュリティベンダーの高度なルールセットも利用可能です。
| プロバイダ | 製品名 | 月額 | 特徴 | 推奨環境 |
|---|---|---|---|---|
| F5 Networks | F5 WAF Rules | $30~ | 高精度検知、AI活用 | エンタープライズ |
| Imperva | ThreatFeed | $50~ | リアルタイム脅威情報 | Eコマース |
| Fortinet | FortiRules | $40~ | 機械学習ベース | 金融機関 |
| Cyber Security Cloud | WafCharm | $45~ | 自動チューニング | 中小企業 |
| Signal Sciences | Advanced Rules | $60~ | DevSecOps統合 | SaaS企業 |
最適な組み合わせパターン
企業規模と要件に応じた、コスト効率の良いルールセット組み合わせを提案します。
- スタートアップ向け(月額$25)
- Core Rule Set($5)+ Rate Limiting(カスタムルール)+ IP Reputation List($20)の組み合わせで、基本的な攻撃の95%を防御できます。SQLインジェクションの基本パターン、DDoS攻撃、既知の悪意あるIPからのアクセスをブロックします。小規模なWebアプリケーションやAPIには十分な防御力です。
- 中小企業向け(月額$45)
- Core Rule Set($5)+ SQL Database Rule Set($20)+ Geographic Restriction(カスタム)+ Known Bad Inputs($5)+ Rate Limiting(カスタム)の構成で、包括的な防御を実現します。日本国内向けサービスなら、海外からのアクセスを制限することで、攻撃の80%を事前に防げます。
- エンタープライズ向け(月額$100+)
- 全AWS Managed Rules(約$70)+ F5 WAF Rules($30)+ カスタムルール群 + IP Intelligence Feed統合により、最高レベルの防御を構築します。複数のレイヤーでの防御により、ゼロデイ攻撃や高度な回避技術にも対応可能です。SOCとの連携により、24時間体制での監視も実現できます。
カスタムルール作成のベストプラクティス
効果的なカスタムルールは、パフォーマンスと防御力のバランスを考慮して設計する必要があります。
効果的なルール設計
カスタムルールの設計では、処理効率と検知精度の両立が重要です。
正規表現パターンの最適化
# 効率的な正規表現パターン設計例
import re
import time
# パフォーマンス比較用のテストコード
class RegexOptimizer:
def __init__(self):
# 悪い例:バックトラックが多く、処理負荷が高い
self.bad_pattern = r".*(\bSELECT\b.*\bFROM\b.*|\bUNION\b.*\bSELECT\b.*|\bINSERT\b.*\bINTO\b.*)"
# 良い例:アンカーと制限を活用し、効率的
self.good_pattern = r"(?i)^.{0,100}(SELECT|UNION|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC)"
# 最適化版:より具体的なパターン
self.optimized_pattern = r"(?i)(?:^|\s|[^a-z])(SELECT\s+[\w\*]+\s+FROM|UNION\s+SELECT|INSERT\s+INTO)"
def test_performance(self, test_strings):
results = {}
for pattern_name, pattern in [
("悪い例", self.bad_pattern),
("良い例", self.good_pattern),
("最適化版", self.optimized_pattern)
]:
compiled = re.compile(pattern)
start_time = time.time()
for test_string in test_strings:
compiled.search(test_string)
elapsed = time.time() - start_time
results[pattern_name] = elapsed
return results
def generate_waf_rule(self, pattern):
"""AWS WAF用のルール生成"""
return {
"Name": "OptimizedSQLiDetection",
"Priority": 100,
"Statement": {
"RegexMatchStatement": {
"RegexString": pattern,
"FieldToMatch": {
"AllQueryArguments": {}
},
"TextTransformations": [
{"Priority": 0, "Type": "URL_DECODE"},
{"Priority": 1, "Type": "LOWERCASE"},
{"Priority": 2, "Type": "COMPRESS_WHITE_SPACE"}
]
}
},
"Action": {"Block": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": True,
"CloudWatchMetricsEnabled": True,
"MetricName": "OptimizedSQLiDetection"
}
}
# 使用例
optimizer = RegexOptimizer()
# テスト用の文字列生成
test_strings = [
"Normal request with some text" * 10,
"SELECT * FROM users WHERE id=1",
"' OR '1'='1' UNION SELECT * FROM passwords",
"普通のリクエスト with 日本語"
] * 100
# パフォーマンステスト実行
results = optimizer.test_performance(test_strings)
# 結果表示
baseline = results["悪い例"]
for name, time_taken in results.items():
improvement = ((baseline / time_taken - 1) * 100) if name != "悪い例" else 0
print(f"{name}: {time_taken:.4f}秒 (改善率: {improvement:+.1f}%)")
# WAFルール生成
waf_rule = optimizer.generate_waf_rule(optimizer.optimized_pattern)
print(f"\n生成されたWAFルール:\n{waf_rule}")
Rate Limitingとの組み合わせ
レート制限は、SQLインジェクション攻撃の試行を効果的に抑制します。
{
"Name": "APIRateLimitWithSQLiProtection",
"Priority": 1,
"Statement": {
"RateBasedStatement": {
"Limit": 100,
"AggregateKeyType": "IP",
"ScopeDownStatement": {
"AndStatement": {
"Statements": [
{
"ByteMatchStatement": {
"SearchString": "/api/",
"FieldToMatch": {
"UriPath": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "LOWERCASE"
}
],
"PositionalConstraint": "STARTS_WITH"
}
},
{
"NotStatement": {
"Statement": {
"IPSetReferenceStatement": {
"ARN": "arn:aws:wafv2:us-east-1:123456789012:global/ipset/trusted-ips/xxxxx"
}
}
}
}
]
}
}
}
},
"Action": {
"Block": {
"CustomResponse": {
"ResponseCode": 429,
"CustomResponseBodyKey": "rate-limit-exceeded",
"ResponseHeaders": [
{
"Name": "Retry-After",
"Value": "60"
},
{
"Name": "X-RateLimit-Limit",
"Value": "100"
}
]
}
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "APIRateLimitWithSQLiProtection"
}
}
地理的制限の実装
攻撃の多くは海外から来るため、地理的制限は効果的な防御層となります。
- 国レベルの制限
- 高リスク国(攻撃の発信源として知られる国)からのアクセスを自動的にブロックします。AWS WAFのGeo Match Statementを使用し、許可する国のリストを定義する「ホワイトリスト方式」が推奨されます。日本国内向けサービスなら、JP(日本)のみを許可し、それ以外をブロックすることで、攻撃の70-80%を防げます。
- IP評価リストの活用
- AWS WAF Fraud Control Account Takeover Prevention(ATP)やBot Controlと連携し、悪意のあるIPアドレスを自動的に識別・ブロックします。Amazon IP Reputation Listには、世界中のハニーポットやセキュリティ研究機関から収集された悪意あるIPが含まれ、リアルタイムで更新されます。
- VPN/Proxy検出
- 匿名化サービス経由のアクセスは、攻撃者が身元を隠すために使用することが多いため、検出・制限することが重要です。AWS WAF Bot Controlの Anonymous IP List機能を使用することで、TorノードやVPNサービスのIPアドレスを識別できます。必要に応じて、CAPTCHAチャレンジを要求することで、正当なユーザーとボットを区別できます。
CloudFront、ALBとの統合設定
AWS WAFの効果を最大化するには、CloudFrontやApplication Load Balancer(ALB)との適切な統合が不可欠です。
CloudFrontでのWAF設定
CloudFrontのエッジロケーションでWAFを動作させることで、グローバルな防御と高速なレスポンスを実現できます。
エッジロケーション活用のメリット
# CloudFrontエッジでのWAF実行による効果
【遅延削減効果】
従来構成(東京リージョンのみ):
- 日本国内: 平均50ms
- アジア太平洋: 平均150ms
- 北米: 平均200ms
- ヨーロッパ: 平均250ms
CloudFrontエッジWAF構成:
- 日本国内: 平均10ms(80%改善)
- アジア太平洋: 平均30ms(80%改善)
- 北米: 平均20ms(90%改善)
- ヨーロッパ: 平均25ms(90%改善)
【コスト最適化効果】
オリジンへのリクエスト削減:
- 総リクエスト数: 1000万/月
- エッジでブロック: 100万(10%)
- キャッシュヒット: 800万(80%)
- オリジン到達: 100万(10%)
→ オリジンへの負荷90%削減
帯域幅コスト削減:
- 削減前: $500/月(10TB転送)
- 削減後: $150/月(3TB転送)
→ 70%のコスト削減
EC2/ALB負荷削減:
- CPU使用率: 60% → 15%
- メモリ使用率: 70% → 20%
- インスタンスサイズ縮小可能
→ EC2コスト50%削減可能
キャッシュ設定との調整
CloudFrontのキャッシュとWAFを最適に組み合わせる設定例です。
// CloudFormationテンプレート(YAML形式)
const cloudFormationTemplate = {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "CloudFront with WAF Integration",
"Resources": {
"WebACL": {
"Type": "AWS::WAFv2::WebACL",
"Properties": {
"Scope": "CLOUDFRONT",
"DefaultAction": {
"Allow": {}
},
"Rules": [
{
"Name": "SQLiProtection",
"Priority": 1,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesSQLiRuleSet"
}
},
"Action": {
"Block": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "SQLiProtection"
}
}
]
}
},
"CloudFrontDistribution": {
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"WebACLId": {
"Fn::GetAtt": ["WebACL", "Arn"]
},
"Origins": [
{
"Id": "ALBOrigin",
"DomainName": "alb.example.com",
"CustomOriginConfig": {
"HTTPPort": 80,
"HTTPSPort": 443,
"OriginProtocolPolicy": "https-only",
"OriginSSLProtocols": ["TLSv1.2"]
}
}
],
"DefaultCacheBehavior": {
"TargetOriginId": "ALBOrigin",
"ViewerProtocolPolicy": "redirect-to-https",
"AllowedMethods": ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"],
"CachedMethods": ["GET", "HEAD", "OPTIONS"],
"CachePolicyId": "658327ea-f89e-4fab-a63d-7e88639e58f6",
"OriginRequestPolicyId": "88a5eaf4-2fd4-4709-b370-b4c650ea3fcf",
"ResponseHeadersPolicyId": "67f04c6a-8e36-4720-a678-344ed4b3357e"
},
"CacheBehaviors": [
{
"PathPattern": "/api/*",
"TargetOriginId": "ALBOrigin",
"ViewerProtocolPolicy": "https-only",
"AllowedMethods": ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"],
"CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad",
"OriginRequestPolicyId": "88a5eaf4-2fd4-4709-b370-b4c650ea3fcf"
},
{
"PathPattern": "/admin/*",
"TargetOriginId": "ALBOrigin",
"ViewerProtocolPolicy": "https-only",
"TrustedSigners": ["self"],
"CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
}
],
"CustomErrorResponses": [
{
"ErrorCode": 403,
"ResponseCode": 403,
"ResponsePagePath": "/error/403.html",
"ErrorCachingMinTTL": 60
}
]
}
}
}
}
};
Application Load Balancer統合
ALBとの統合により、アプリケーションレイヤーでの詳細な制御が可能になります。
| 設定項目 | 推奨値 | 理由 | 設定方法 |
|---|---|---|---|
| 評価位置 | リクエスト前 | 不要な負荷を削減 | ALB リスナールールの最上位 |
| ロギング | S3バケット | 長期保存と分析 | ALB アクセスログ有効化 |
| サンプリング | 100% | 完全な可視化 | WAF ロギング設定 |
| メトリクス | CloudWatch | リアルタイム監視 | 詳細メトリクス有効化 |
| ヘルスチェック | 除外 | 誤検知防止 | ヘルスチェックパスを除外 |
| タイムアウト | 30秒 | SQLi時間攻撃対策 | ALB アイドルタイムアウト |
API Gateway保護
API GatewayでのWAF統合により、APIエンドポイントを保護します。
# Terraform による API Gateway + WAF 設定
terraform_config = """
# WAF Web ACL
resource "aws_wafv2_web_acl" "api_protection" {
name = "api-gateway-waf"
scope = "REGIONAL"
default_action {
allow {}
}
rule {
name = "SQLiProtection"
priority = 1
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesSQLiRuleSet"
vendor_name = "AWS"
excluded_rule {
name = "SQLi_QUERYARGUMENTS"
}
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "SQLiProtectionMetric"
sampled_requests_enabled = true
}
}
rule {
name = "RateLimiting"
priority = 2
action {
block {}
}
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "RateLimitingMetric"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "APIProtectionMetric"
sampled_requests_enabled = true
}
}
# API Gateway REST API
resource "aws_api_gateway_rest_api" "main" {
name = "protected-api"
endpoint_configuration {
types = ["REGIONAL"]
}
}
# WAF Association
resource "aws_wafv2_web_acl_association" "api_gateway" {
resource_arn = aws_api_gateway_stage.prod.arn
web_acl_arn = aws_wafv2_web_acl.api_protection.arn
}
# API Gateway Method Settings
resource "aws_api_gateway_method_settings" "settings" {
rest_api_id = aws_api_gateway_rest_api.main.id
stage_name = aws_api_gateway_stage.prod.stage_name
method_path = "*/*"
settings {
throttling_rate_limit = 1000
throttling_burst_limit = 2000
logging_level = "ERROR"
data_trace_enabled = true
metrics_enabled = true
# WAF統合でのキャッシュ設定
caching_enabled = true
cache_ttl_in_seconds = 300
cache_data_encrypted = true
}
}
# API Gateway Stage
resource "aws_api_gateway_stage" "prod" {
deployment_id = aws_api_gateway_deployment.main.id
rest_api_id = aws_api_gateway_rest_api.main.id
stage_name = "prod"
xray_tracing_enabled = true
access_log_settings {
destination_arn = aws_cloudwatch_log_group.api_gateway.arn
format = jsonencode({
requestId = "$context.requestId"
ip = "$context.identity.sourceIp"
requestTime = "$context.requestTime"
httpMethod = "$context.httpMethod"
routeKey = "$context.routeKey"
status = "$context.status"
protocol = "$context.protocol"
responseLength = "$context.responseLength"
error = "$context.error.message"
wafResponse = "$context.wafResponseCode"
})
}
}
"""
ログ分析とモニタリング設定
効果的なログ分析により、攻撃の早期発見と対応が可能になります。
CloudWatch Insightsクエリ例
CloudWatch Logs Insightsを使用した、SQLインジェクション攻撃の詳細分析です。
SQLインジェクション攻撃の分析
-- 1. 攻撃パターン分析クエリ(上位攻撃者の特定)
fields @timestamp, httpRequest.clientIp as ClientIP,
httpRequest.uri as URI,
httpRequest.args as QueryString,
terminatingRuleId as BlockRule,
action as Action
| filter action = "BLOCK"
| filter terminatingRuleId like /SQL/
| stats count() as AttackCount by ClientIP
| sort AttackCount desc
| limit 20
-- 2. 時系列攻撃傾向(5分間隔でのブロック数推移)
fields @timestamp, action, terminatingRuleId
| filter action = "BLOCK"
| filter terminatingRuleId like /SQL/
| stats count() as BlockedRequests by bin(@timestamp, 5m) as TimeWindow
| sort TimeWindow desc
-- 3. 攻撃対象URLの分析
fields httpRequest.uri as TargetURL,
httpRequest.httpMethod as Method
| filter action = "BLOCK"
| filter terminatingRuleId like /SQL/
| stats count() as Attacks by TargetURL, Method
| sort Attacks desc
| limit 50
-- 4. 攻撃ペイロードの詳細分析
fields @timestamp,
httpRequest.clientIp as AttackerIP,
httpRequest.uri as URI,
httpRequest.args as Payload,
terminatingRuleMatchDetails[0].conditionEvaluations[0].matchedData as MatchedPattern
| filter action = "BLOCK"
| filter terminatingRuleId like /SQLi/
| sort @timestamp desc
| limit 100
-- 5. 地理的分布分析
fields httpRequest.country as Country,
httpRequest.clientIp as IP
| filter action = "BLOCK"
| stats count() as Attacks by Country
| sort Attacks desc
-- 6. User-Agent分析(ボット検出)
fields httpRequest.headers[?name=='User-Agent'].value as UserAgent
| filter action = "BLOCK"
| stats count() as Count by UserAgent
| sort Count desc
| limit 20
アラート設定
段階的なアラート設定により、適切なエスカレーションを実現します。
- Critical(緊急対応)- 即座にページャー通知
- 5分間で同一IPから100回以上のSQLインジェクション検知、または異なる10個以上のIPから同時攻撃を検知した場合。これは組織的な攻撃やボットネット攻撃の可能性が高く、即座の対応が必要です。自動的にIPをブロックリストに追加し、セキュリティチームに電話通知を送信します。インシデント対応プロセスを自動起動し、証拠保全を開始します。
- Warning(要確認)- Slackまたはメール通知
- 新規の攻撃パターン検出、通常の3倍以上のブロック率、または特定のURLに対する集中攻撃を検知した場合。これらは潜在的な脅威として、営業時間内に確認が必要です。ログを自動的にS3に保存し、分析レポートを生成します。必要に応じて、追加のWAFルールを検討します。
- Info(記録のみ)- ログ記録とダッシュボード更新
- 既知パターンの単発検知、低リスク国からの散発的アクセス、または誤検知の可能性が高いケース。これらは統計情報として記録し、週次・月次レポートに含めます。パターン分析により、将来の攻撃予測に活用します。
Security Hubとの統合
AWS Security Hubとの統合により、セキュリティ態勢の一元管理を実現します。
{
"SecurityHubIntegration": {
"Enabled": true,
"FindingPublishing": {
"Severity": ["CRITICAL", "HIGH", "MEDIUM"],
"Types": [
"Software and Configuration Checks/AWS Security Best Practices",
"Sensitive Data Identifications/PII",
"TTPs/Initial Access/SQL Injection"
],
"ProductArn": "arn:aws:securityhub:us-east-1:123456789012:product/123456789012/default"
},
"AutoRemediation": {
"Enabled": true,
"LambdaFunction": "arn:aws:lambda:us-east-1:123456789012:function:WAFAutoRemediation",
"Actions": [
{
"Type": "BlockIP",
"Threshold": 50,
"Duration": 3600
},
{
"Type": "NotifySOC",
"Channel": "security-alerts",
"Priority": "HIGH"
},
{
"Type": "CreateTicket",
"System": "ServiceNow",
"Template": "security-incident"
},
{
"Type": "EnableEnhancedMonitoring",
"Target": "SourceIP",
"Duration": 86400
}
]
},
"ComplianceMapping": {
"PCI-DSS": ["6.5.1", "6.6"],
"ISO27001": ["A.14.2.5", "A.13.1.1"],
"NIST": ["SI-10", "SC-5"]
}
}
}
月額コストの試算と最適化
AWS WAFのコストを正確に把握し、最適化することで、費用対効果の高い運用を実現できます。
コスト最適化テクニック
効果的なコスト削減施策とその実装方法を紹介します。
| 施策 | 削減率 | 実装難易度 | 実装方法 | 注意点 |
|---|---|---|---|---|
| 不要ルール削除 | 20-30% | 低 | 使用頻度の低いルールを特定して削除 | セキュリティレベル低下リスク |
| サンプリング設定 | 10-15% | 低 | ログのサンプリングレートを調整 | 完全な可視性の喪失 |
| リージョン集約 | 15-20% | 中 | 複数リージョンのWAFを統合 | レイテンシー増加の可能性 |
| Reserved Capacity | 25% | 低 | 年間契約による割引適用 | 柔軟性の低下 |
| ログ階層化 | 30-40% | 中 | S3 Intelligent-Tiering活用 | アクセス速度の低下 |
実装手順とテンプレート
Infrastructure as Codeを活用した、再現性のある実装方法を提供します。
Infrastructure as Codeでの展開
AWS CDKを使用した、モダンな実装アプローチです。
CDKでの実装例
// AWS CDK v2 での WAF 実装
import * as cdk from 'aws-cdk-lib';
import * as wafv2 from 'aws-cdk-lib/aws-wafv2';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as logs from 'aws-cdk-lib/aws-logs';
import { Construct } from 'constructs';
export class ComprehensiveWAFStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// ログ用S3バケット
const logBucket = new s3.Bucket(this, 'WAFLogBucket', {
bucketName: `waf-logs-${this.account}-${this.region}`,
encryption: s3.BucketEncryption.S3_MANAGED,
lifecycleRules: [{
id: 'DeleteOldLogs',
expiration: cdk.Duration.days(90),
transitions: [{
storageClass: s3.StorageClass.INTELLIGENT_TIERING,
transitionAfter: cdk.Duration.days(30)
}]
}],
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL
});
// IPセット(信頼できるIP)
const trustedIpSet = new wafv2.CfnIPSet(this, 'TrustedIPs', {
scope: 'CLOUDFRONT',
ipAddressVersion: 'IPV4',
addresses: [
'10.0.0.0/8', // 内部ネットワーク
'192.168.0.0/16', // プライベートネットワーク
]
});
// カスタムレスポンスボディ
const customResponseBodies = {
'blocked-request': {
content: JSON.stringify({
error: 'Access Denied',
message: 'Your request has been blocked due to security reasons.',
reference: '{{request_id}}'
}),
contentType: 'APPLICATION_JSON'
},
'rate-limit-exceeded': {
content: JSON.stringify({
error: 'Too Many Requests',
message: 'Rate limit exceeded. Please try again later.'
}),
contentType: 'APPLICATION_JSON'
}
};
// Web ACL
const webAcl = new wafv2.CfnWebACL(this, 'WebACL', {
scope: 'CLOUDFRONT',
defaultAction: { allow: {} },
customResponseBodies: customResponseBodies,
rules: [
// 1. IP許可リスト
{
name: 'AllowTrustedIPs',
priority: 1,
statement: {
ipSetReferenceStatement: {
arn: trustedIpSet.attrArn
}
},
action: { allow: {} },
visibilityConfig: {
sampledRequestsEnabled: true,
cloudWatchMetricsEnabled: true,
metricName: 'AllowTrustedIPs'
}
},
// 2. レート制限
{
name: 'RateLimiting',
priority: 10,
statement: {
rateBasedStatement: {
limit: 2000,
aggregateKeyType: 'IP'
}
},
action: {
block: {
customResponse: {
responseCode: 429,
customResponseBodyKey: 'rate-limit-exceeded'
}
}
},
visibilityConfig: {
sampledRequestsEnabled: true,
cloudWatchMetricsEnabled: true,
metricName: 'RateLimiting'
}
},
// 3. AWS Managed Rules - Core Rule Set
{
name: 'AWSManagedRulesCommonRuleSet',
priority: 20,
overrideAction: { none: {} },
statement: {
managedRuleGroupStatement: {
vendorName: 'AWS',
name: 'AWSManagedRulesCommonRuleSet',
excludedRules: [
{ name: 'SizeRestrictions_BODY' },
{ name: 'GenericRFI_BODY' }
]
}
},
visibilityConfig: {
sampledRequestsEnabled: true,
cloudWatchMetricsEnabled: true,
metricName: 'CommonRuleSetMetric'
}
},
// 4. AWS Managed Rules - SQL Database
{
name: 'AWSManagedRulesSQLiRuleSet',
priority: 30,
overrideAction: { none: {} },
statement: {
managedRuleGroupStatement: {
vendorName: 'AWS',
name: 'AWSManagedRulesSQLiRuleSet',
scopeDownStatement: {
notStatement: {
statement: {
byteMatchStatement: {
searchString: '/admin/',
fieldToMatch: { uriPath: {} },
positionalConstraint: 'STARTS_WITH',
textTransformations: [{
priority: 0,
type: 'LOWERCASE'
}]
}
}
}
}
}
},
visibilityConfig: {
sampledRequestsEnabled: true,
cloudWatchMetricsEnabled: true,
metricName: 'SQLiRuleSetMetric'
}
},
// 5. カスタムSQLインジェクション検知
{
name: 'CustomSQLiDetection',
priority: 40,
statement: {
orStatement: {
statements: [
{
sqliMatchStatement: {
fieldToMatch: {
allQueryArguments: {}
},
textTransformations: [
{ priority: 0, type: 'URL_DECODE' },
{ priority: 1, type: 'HTML_ENTITY_DECODE' },
{ priority: 2, type: 'LOWERCASE' }
]
}
},
{
regexMatchStatement: {
regexString: '(?i)(union.*select|select.*from|insert.*into|delete.*from)',
fieldToMatch: {
body: {
oversizeHandling: 'MATCH'
}
},
textTransformations: [
{ priority: 0, type: 'URL_DECODE' },
{ priority: 1, type: 'LOWERCASE' }
]
}
}
]
}
},
action: {
block: {
customResponse: {
responseCode: 403,
customResponseBodyKey: 'blocked-request'
}
}
},
visibilityConfig: {
sampledRequestsEnabled: true,
cloudWatchMetricsEnabled: true,
metricName: 'CustomSQLiDetection'
}
},
// 6. 地理的制限(日本のみ許可)
{
name: 'GeoRestriction',
priority: 50,
statement: {
notStatement: {
statement: {
geoMatchStatement: {
countryCodes: ['JP', 'US'] // 日本とアメリカのみ許可
}
}
}
},
action: {
block: {
customResponse: {
responseCode: 403,
customResponseBodyKey: 'blocked-request'
}
}
},
visibilityConfig: {
sampledRequestsEnabled: true,
cloudWatchMetricsEnabled: true,
metricName: 'GeoRestriction'
}
}
],
visibilityConfig: {
sampledRequestsEnabled: true,
cloudWatchMetricsEnabled: true,
metricName: 'WebACL'
}
});
// ログ設定
const logConfig = new wafv2.CfnLoggingConfiguration(this, 'WAFLogging', {
resourceArn: webAcl.attrArn,
logDestinationConfigs: [
`arn:aws:s3:::${logBucket.bucketName}/waf-logs/`
],
loggingFilter: {
defaultBehavior: 'KEEP',
filters: [
{
behavior: 'DROP',
requirement: 'MEETS_ANY',
conditions: [
{
actionCondition: {
action: 'ALLOW'
}
}
]
}
]
}
});
// CloudWatch Alarms
const sqlInjectionAlarm = new cloudwatch.Alarm(this, 'SQLInjectionAlarm', {
metric: new cloudwatch.Metric({
namespace: 'AWS/WAFV2',
metricName: 'BlockedRequests',
dimensionsMap: {
Rule: 'CustomSQLiDetection',
WebACL: webAcl.name!,
Region: 'GLOBAL'
},
statistic: 'Sum',
period: cdk.Duration.minutes(5)
}),
threshold: 100,
evaluationPeriods: 1,
treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING
});
// Outputs
new cdk.CfnOutput(this, 'WebACLArn', {
value: webAcl.attrArn,
description: 'Web ACL ARN for CloudFront association'
});
new cdk.CfnOutput(this, 'LogBucketName', {
value: logBucket.bucketName,
description: 'S3 bucket for WAF logs'
});
}
}
段階的導入プラン
リスクを最小化しながら、確実にWAFを導入するための段階的アプローチです。
- Phase 1(週1-2):監視モード
- すべてのルールをCount modeに設定し、実際の攻撃をブロックせずに検知のみ行います。この期間に、正常なトラフィックパターンを学習し、誤検知となる可能性があるリクエストを特定します。ログを詳細に分析し、業務に影響を与える可能性があるルールを洗い出します。社内からのテストアクセスを行い、管理画面や特殊な機能が正常に動作することを確認します。
- Phase 2(週3-4):部分適用
- 明確な攻撃パターン(SQLインジェクションの典型的なペイロード)のみをBlock modeに変更し、その他はCount modeを継続します。段階的にブロック対象を増やし、各段階で24時間の監視期間を設けます。誤検知が発生した場合は、即座にルールを調整またはCount modeに戻します。この期間に、ホワイトリストやカスタムルールの作成を行います。
- Phase 3(週5-6):本番適用
- すべてのルールをBlock modeに変更し、本格的な防御を開始します。例外設定やカスタムルールの調整が完了し、誤検知率が0.1%以下になることを確認します。24時間体制での監視を行い、問題が発生した場合の緊急対応手順を確立します。すべてのステークホルダーに運用開始を通知し、問い合わせ窓口を明確にします。
- Phase 4(週7-8):最適化
- 蓄積されたデータを基に、パフォーマンスとコストの最適化を行います。使用頻度の低いルールを削除し、頻繁に実行されるルールの処理順序を最適化します。CloudFrontのキャッシュ設定と連携し、オリジンへの負荷を最小化します。月次レビュープロセスを確立し、継続的な改善サイクルを構築します。
トラブルシューティング
運用中に発生する一般的な問題と、その解決方法を解説します。
よくある問題と解決方法
実際の運用で頻繁に遭遇する問題への対処法です。
誤検知への対処
| 症状 | 原因 | 対策 | 予防策 |
|---|---|---|---|
| 正常リクエストがブロック | ルール感度が高すぎる | 感度を1段階下げる、除外ルール追加 | 段階的な感度調整 |
| 特定ユーザーのみ影響 | 特殊文字や日本語の使用 | 該当IPをホワイトリスト登録 | 文字エンコーディング検証 |
| API呼び出しエラー | ペイロードサイズ超過 | サイズ制限を8KBから64KBに調整 | API仕様の事前確認 |
| 管理画面アクセス不可 | HTMLコード含むコンテンツ | 管理パスを除外設定 | 管理URLの事前登録 |
| ファイルアップロード失敗 | Base64データの誤検知 | アップロードパスを除外 | 専用エンドポイント設計 |
パフォーマンス問題
WAF導入によるレイテンシー影響を測定し、対策を講じます。
#!/bin/bash
# WAFパフォーマンス測定スクリプト
echo "=== AWS WAF Performance Testing ==="
echo "Date: $(date)"
echo ""
# テスト対象URL
DIRECT_URL="https://origin.example.com/api/test"
WAF_URL="https://waf-protected.example.com/api/test"
ITERATIONS=100
# 関数:レイテンシ測定
measure_latency() {
local url=$1
local name=$2
local results=()
echo "Testing $name ($url)..."
for i in $(seq 1 $ITERATIONS); do
# curl で応答時間を測定
time=$(curl -w "%{time_total}" -o /dev/null -s "$url")
results+=($time)
# プログレス表示
if [ $((i % 10)) -eq 0 ]; then
echo -n "."
fi
done
echo " Done!"
# 統計計算
total=0
min=999999
max=0
for time in "${results[@]}"; do
total=$(echo "$total + $time" | bc)
if (( $(echo "$time < $min" | bc -l) )); then
min=$time
fi
if (( $(echo "$time > $max" | bc -l) )); then
max=$time
fi
done
avg=$(echo "scale=4; $total / $ITERATIONS" | bc)
# 結果表示
echo "Results for $name:"
echo " Average: ${avg}s"
echo " Min: ${min}s"
echo " Max: ${max}s"
echo ""
# 配列を返す
echo "${results[@]}"
}
# 直接アクセスの測定
echo "1. Direct Access (No WAF)"
direct_results=$(measure_latency "$DIRECT_URL" "Direct")
# WAF経由の測定
echo "2. WAF Protected Access"
waf_results=$(measure_latency "$WAF_URL" "WAF")
# オーバーヘッド計算
echo "3. Performance Impact Analysis"
direct_avg=$(echo "$direct_results" | awk '{sum=0; for(i=1;i<=NF;i++)sum+=$i; print sum/NF}')
waf_avg=$(echo "$waf_results" | awk '{sum=0; for(i=1;i<=NF;i++)sum+=$i; print sum/NF}')
overhead=$(echo "scale=2; ($waf_avg - $direct_avg) * 1000" | bc)
overhead_percent=$(echo "scale=2; (($waf_avg / $direct_avg) - 1) * 100" | bc)
echo "WAF Overhead: ${overhead}ms (${overhead_percent}%)"
# 推奨事項
echo ""
echo "4. Recommendations:"
if (( $(echo "$overhead_percent > 20" | bc -l) )); then
echo " ⚠️ High overhead detected. Consider:"
echo " - Reducing rule complexity"
echo " - Enabling CloudFront caching"
echo " - Optimizing regex patterns"
elif (( $(echo "$overhead_percent > 10" | bc -l) )); then
echo " ⚠️ Moderate overhead. Consider:"
echo " - Reviewing rule priorities"
echo " - Removing unnecessary transformations"
else
echo " ✅ Overhead is within acceptable range"
fi
# CloudWatch カスタムメトリクス送信
aws cloudwatch put-metric-data \
--namespace "Custom/WAF" \
--metric-name "Latency" \
--dimensions Endpoint=Direct \
--value "$direct_avg" \
--unit Seconds
aws cloudwatch put-metric-data \
--namespace "Custom/WAF" \
--metric-name "Latency" \
--dimensions Endpoint=WAF \
--value "$waf_avg" \
--unit Seconds
echo ""
echo "Metrics sent to CloudWatch successfully!"
よくある質問(FAQ)
- Q: AWS WAFとCloudflare WAFどちらが良いですか?
- A: AWS環境を中心に構築されているシステムなら、AWS WAFが統合性とコスト効率で優れています。CloudFront、ALB、API Gatewayとのネイティブ統合により、設定や管理が簡単で、IAMによる細かい権限管理も可能です。料金は従量課金制で、月1000万リクエストなら約$76(約11,400円)程度です。一方、Cloudflareは固定料金制(Pro版$20/月)で、DDoS対策も含まれており、マルチクラウド環境やCDNを重視する場合に有利です。AWSインフラが中心なら AWS WAF、グローバル展開やマルチクラウドなら Cloudflare を推奨します。どちらも[SQLインジェクション対策](/security/web-api/sql-injection/)として十分な機能を提供しています。
- Q: マネージドルールとカスタムルールの使い分けは?
- A: まずAWS Managed Rules(特にCore Rule Set)で基本的な防御体制を構築することを推奨します。これにより、[OWASP Top 10](/security/web-api/)に対応した包括的な保護が即座に実現できます。その後、自社の業務特性に応じてカスタムルールを追加していきます。例えば、日本語サイトなら海外からのアクセスを制限する地理的制限、APIならRate Limitingによる過剰アクセス防止、管理画面なら特定IPのみ許可するなどです。一般的な配分として、マネージドルールで攻撃の80%を防ぎ、カスタムルールで残り20%の業務固有のリスクに対応するイメージです。コストと運用負荷のバランスを考慮し、段階的に最適化していくことが重要です。
- Q: ログの保存期間とコストはどう考えればよいですか?
- A: 通常の運用では3ヶ月の保存を推奨します。これは、攻撃パターンの分析とインシデント調査に十分な期間です。S3 Intelligent-Tieringを使用することで、アクセス頻度に応じて自動的にストレージクラスが変更され、コストが最適化されます。月1000万リクエストの場合、ログ保存コストは約$10/月程度です。コンプライアンス要件(PCI DSS、個人情報保護法等)がある場合は、1年以上の保存が必要になることもあります。この場合、90日以降のログをS3 Glacier Deep Archiveに移行することで、コストを約80%削減できます。分析用途では、直近1週間分をCloudWatch Logsに、1ヶ月分をS3 Standard に、それ以前をS3 Glacier に保存する階層化戦略が効果的です。
- Q: WAF導入後もアプリケーションの脆弱性対策は必要ですか?
- A: はい、絶対に必要です。WAFは「仮想パッチ」として機能し、既知の攻撃パターンをブロックしますが、根本的な解決ではありません。[プレースホルダ](/security/web-api/sql-injection/column/placeholder-implementation/)や[適切なエスケープ処理](/security/web-api/sql-injection/column/escape-processing/)などの実装レベルの対策は継続的に行う必要があります。WAFは多層防御の一層であり、アプリケーション側のセキュア開発、定期的な脆弱性診断、迅速なパッチ適用と組み合わせることで、真の安全性が実現されます。WAFで時間を稼ぎながら、根本的な脆弱性を修正していくアプローチが理想的です。
- Q: CloudFrontを使用していない場合でもAWS WAFは使えますか?
- A: はい、使用できます。AWS WAFはREGIONALスコープとCLOUDFRONTスコープの2種類があり、REGIONALスコープではApplication Load Balancer(ALB)、API Gateway、AppSync GraphQL API、Cognito User Pool、App Runner、Verified Access に直接適用できます。ただし、CloudFrontと組み合わせることで、エッジロケーションでの防御により、レイテンシー削減とオリジンの負荷軽減という追加のメリットが得られます。既存のアーキテクチャを大きく変更せずにWAFを導入したい場合は、まずALBにREGIONAL WAFを適用し、段階的にCloudFrontの導入を検討することをお勧めします。
まとめ
AWS WAFは、AWSエコシステムにおける SQLインジェクション対策の要となるサービスです。適切に設定・運用することで、高度な攻撃からWebアプリケーションを守ることができます。
AWS WAF導入の重要ポイント:
-
段階的な導入アプローチ
- Count modeから始めて誤検知を最小化
- 2-3週間かけて慎重に調整
- 本番適用後も継続的な最適化
-
コスト効率の最大化
- 月額$76程度から本格的な防御が可能
- 不要なルールの削除で20-30%のコスト削減
- S3 Intelligent-Tieringでログコストを最適化
-
統合による相乗効果
- CloudFrontとの組み合わせでグローバル防御
- Security Hubで一元的なセキュリティ管理
- CloudWatch Insightsで詳細な攻撃分析
-
継続的な改善サイクル
- 週次でのルール見直し
- 月次でのKPI評価
- 四半期ごとの大規模レビュー
特に重要なのは、WAFを「設定して終わり」ではなく、継続的に改善していくことです。攻撃手法は日々進化しており、それに対応するためには、定期的なルールの更新と最適化が不可欠です。
AWS WAFは、中小企業から大企業まで、規模に応じた柔軟な防御を提供します。Infrastructure as Codeによる管理により、複数環境への展開も容易で、DevSecOpsの実践にも適しています。
最後に、WAFは万能ではありません。包括的なWebセキュリティ対策の一部として位置づけ、アプリケーションレベルの対策と組み合わせることで、真の安全性を実現してください。
【重要なお知らせ】
- 本記事は一般的な情報提供を目的としており、個別の状況に対する助言ではありません
- AWS WAFの仕様と価格は変更される可能性があります(2025年1月時点の情報)
- 実装の際は、AWS公式ドキュメントで最新情報を確認してください
- セキュリティ設定は定期的に見直し、最新の脅威に対応することが重要です
更新履歴
- 初稿公開