AWS WAF ile Web Uygulama Güvenliğini Sağlama
Web uygulamalarına yönelik saldırılar her geçen gün daha sofistike hale geliyor. SQL injection, XSS, bot trafiği, DDoS… Bunları manuel olarak yönetmek artık neredeyse imkansız. AWS WAF (Web Application Firewall) tam da bu noktada devreye giriyor ve doğru yapılandırıldığında gerçek anlamda güçlü bir koruma katmanı sunuyor. Bu yazıda AWS WAF’ı sıfırdan yapılandırmayı, managed rule gruplarını kullanmayı ve maliyet optimizasyonunu gerçek dünya senaryolarıyla ele alacağız.
AWS WAF Nedir ve Nasıl Çalışır
AWS WAF, HTTP/HTTPS trafiğini uygulama katmanında (Layer 7) filtreleyen bir güvenlik servisidir. CloudFront, Application Load Balancer, API Gateway ve AppSync ile entegre çalışır. Temel mantığı oldukça basittir: gelen her istek belirlediğin kurallara göre değerlendirilir ve ya izin verilir, ya engellenir ya da sayılır.
WAF’ın çalışma mantığını anlamak için üç temel kavramı bilmek gerekiyor:
- Web ACL (Access Control List): Kuralları barındıran ana container. Her Web ACL’ye bir veya birden fazla kural grubu eklenir.
- Rule Group: Birden fazla kuralı bir arada tutan yapı. AWS’nin hazır sunduğu managed rule grupları veya kendi yazdığın özel kurallar olabilir.
- Rule: Trafiği değerlendiren temel birim. Her kural bir koşul içerir ve eşleşme durumunda bir aksiyon belirler (Allow, Block, Count, CAPTCHA).
Bir istek Web ACL’e geldiğinde kurallar öncelik sırasına göre değerlendirilir. İlk eşleşen kuralın aksiyonu uygulanır ve değerlendirme durur. Bu yüzden kural öncelikleri kritik önem taşıyor.
AWS CLI ile WAF Kurulumu
AWS Console üzerinden WAF yapılandırmak mümkün olsa da production ortamlarında her şeyi kod olarak yönetmek gerekiyor. Önce temel bir Web ACL oluşturalım:
# Web ACL oluşturma (CloudFront için CLOUDFRONT scope kullanılır)
aws wafv2 create-web-acl
--name "production-web-acl"
--scope REGIONAL
--default-action Allow={}
--rules file://rules.json
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=ProductionWebACL
--region eu-west-1
Burada --scope REGIONAL parametresi ALB veya API Gateway için kullanılır. CloudFront ile kullanacaksan --scope CLOUDFRONT ve --region us-east-1 olması zorunlu. Bu küçük ama kritik bir detay.
Mevcut Web ACL’leri listelemek için:
# Regional Web ACL'leri listele
aws wafv2 list-web-acls
--scope REGIONAL
--region eu-west-1
--query 'WebACLs[*].{Name:Name,Id:Id,ARN:ARN}'
--output table
# Belirli bir Web ACL'nin detaylarını görüntüle
aws wafv2 get-web-acl
--name "production-web-acl"
--scope REGIONAL
--id "your-web-acl-id"
--region eu-west-1
Managed Rule Grupları
AWS ve üçüncü parti sağlayıcılar tarafından sunulan managed rule grupları, güvenlik ekibi olmayan küçük-orta ölçekli şirketler için büyük kolaylık sağlar. AWS’nin ücretsiz sunduğu temel gruplar şunlar:
- AWSManagedRulesCommonRuleSet: OWASP Top 10 tehditlerine karşı temel koruma
- AWSManagedRulesKnownBadInputsRuleSet: Bilinen kötü niyetli input pattern’leri
- AWSManagedRulesSQLiRuleSet: SQL injection saldırılarına özel koruma
- AWSManagedRulesLinuxRuleSet: Linux tabanlı sistemlere yönelik saldırılar
- AWSManagedRulesAmazonIpReputationList: Amazon’un kötü IP listesi
Bu rule gruplarını Web ACL’e eklemek için JSON dosyası oluşturalım:
cat > rules.json << 'EOF'
[
{
"Name": "AWSManagedRulesCommonRuleSet",
"Priority": 10,
"OverrideAction": {
"None": {}
},
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet",
"ExcludedRules": [
{
"Name": "SizeRestrictions_BODY"
}
]
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "CommonRuleSet"
}
},
{
"Name": "AWSManagedRulesSQLiRuleSet",
"Priority": 20,
"OverrideAction": {
"None": {}
},
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesSQLiRuleSet"
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "SQLiRuleSet"
}
}
]
EOF
Dikkat etmem gereken bir nokta: ExcludedRules içine aldığın kurallar Count moduna geçer, tamamen devre dışı kalmaz. Büyük dosya yüklemeleri yapan bir uygulamada SizeRestrictions_BODY kuralını exclude etmezsen kullanıcıların upload işlemleri bloklanır.
Rate Limiting ile Bot Koruması
Rate limiting, belirli bir IP adresinden gelen istek sayısını sınırlandırarak brute force ve credential stuffing saldırılarına karşı koruma sağlar. Login endpoint’lerine yönelik rate limiting kuralı ekleyelim:
# Rate-based rule JSON dosyası oluştur
cat > rate-limit-rule.json << 'EOF'
{
"Name": "RateLimitLoginEndpoint",
"Priority": 5,
"Action": {
"Block": {}
},
"Statement": {
"RateBasedStatement": {
"Limit": 100,
"AggregateKeyType": "IP",
"ScopeDownStatement": {
"ByteMatchStatement": {
"SearchString": "/api/v1/login",
"FieldToMatch": {
"UriPath": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "LOWERCASE"
}
],
"PositionalConstraint": "STARTS_WITH"
}
}
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "RateLimitLogin"
}
}
EOF
# Mevcut Web ACL'e yeni kural ekle
aws wafv2 update-web-acl
--name "production-web-acl"
--scope REGIONAL
--id "your-web-acl-id"
--lock-token "your-lock-token"
--default-action Allow={}
--rules file://rate-limit-rule.json
--visibility-config SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=ProductionWebACL
--region eu-west-1
Limit değeri 5 dakikalık pencerede bir IP’den gelebilecek maksimum istek sayısını belirtir. 100 değeri çoğu login sayfası için makul bir başlangıç noktası. Ancak bu değeri kör koyma; önce Count modunda çalıştır, CloudWatch loglarına bak, meşru trafiği analiz et, sonra Block moduna geç.
Gerçek Dünya Senaryosu: E-ticaret Sitesi
Büyük bir e-ticaret müşterimde yaşanan olayı paylaşayım. Kampanya dönemlerinde bot trafiği fırladı ve gerçek kullanıcıların sepet işlemleri yavaşlamaya başladı. Analiz ettik, üç farklı saldırı tipi vardı:
Senaryo 1: Yüzlerce farklı IP’den saniyede binlerce ürün sayfası tarama (scraping) Senaryo 2: Belirli SKU’lara yönelik stok sorgulama botu Senaryo 3: Checkout sayfasına credential stuffing
Bu üç senaryo için farklı çözümler uyguladık. Önce IP setleri oluşturduk:
# Engellenmesi gereken IP'leri içeren IP set oluştur
aws wafv2 create-ip-set
--name "blocked-ips"
--scope REGIONAL
--ip-address-version IPV4
--addresses "192.0.2.0/24" "198.51.100.0/24"
--region eu-west-1
# IP set ARN'ını al
aws wafv2 get-ip-set
--name "blocked-ips"
--scope REGIONAL
--id "your-ip-set-id"
--region eu-west-1
# Güvenilir IP'leri whitelist'e al (ofis IP'leri, monitoring servisleri vb.)
aws wafv2 create-ip-set
--name "whitelisted-ips"
--scope REGIONAL
--ip-address-version IPV4
--addresses "203.0.113.100/32" "203.0.113.101/32"
--region eu-west-1
Scraping için header tabanlı bir kural yazdık. Bot trafiğinin çoğu User-Agent kontrolünden geçemez:
cat > bot-detection-rule.json << 'EOF'
{
"Name": "BlockMissingUserAgent",
"Priority": 1,
"Action": {
"Block": {
"CustomResponse": {
"ResponseCode": 403,
"CustomResponseBodyKey": "bot-blocked"
}
}
},
"Statement": {
"AndStatement": {
"Statements": [
{
"NotStatement": {
"Statement": {
"ByteMatchStatement": {
"SearchString": "Mozilla",
"FieldToMatch": {
"SingleHeader": {
"Name": "user-agent"
}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "NONE"
}
],
"PositionalConstraint": "CONTAINS"
}
}
}
},
{
"ByteMatchStatement": {
"SearchString": "/products/",
"FieldToMatch": {
"UriPath": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "NONE"
}
],
"PositionalConstraint": "STARTS_WITH"
}
}
]
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "BlockMissingUserAgent"
}
}
EOF
WAF Loglarını Aktifleştirme ve Analiz
WAF’ı kurmak tek başına yeterli değil. Logları aktifleştirmezsen ne bloklandığını, ne atlandığını göremezsin. Logları Kinesis Firehose üzerinden S3’e aktaralım:
# Önce Kinesis Firehose delivery stream oluştur
aws firehose create-delivery-stream
--delivery-stream-name "aws-waf-logs-production"
--s3-destination-configuration
RoleARN="arn:aws:iam::123456789012:role/firehose-role",
BucketARN="arn:aws:s3:::my-waf-logs-bucket",
Prefix="waf-logs/year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/",
ErrorOutputPrefix="waf-logs-errors/",
BufferingHints={SizeInMBs=128,IntervalInSeconds=300}
--region eu-west-1
# WAF logging konfigürasyonu etkinleştir
aws wafv2 put-logging-configuration
--logging-configuration
ResourceArn="arn:aws:wafv2:eu-west-1:123456789012:regional/webacl/production-web-acl/your-id",
LogDestinationConfigs="arn:aws:firehose:eu-west-1:123456789012:deliverystream/aws-waf-logs-production"
--region eu-west-1
Loglar S3’e düştükten sonra Athena ile sorgulayabilirsin. En çok engellenen IP’leri bulmak için basit bir sorgu:
# Athena tablosu oluştur (bu DDL'i Athena console'da çalıştır)
# Sonra CLI üzerinden Athena sorgusu çalıştır
aws athena start-query-execution
--query-string "
SELECT httpRequest.clientIp,
COUNT(*) as request_count,
COUNT(CASE WHEN action = 'BLOCK' THEN 1 END) as blocked_count
FROM waf_logs
WHERE from_iso8601_timestamp(timestamp) > current_timestamp - interval '24' hour
GROUP BY httpRequest.clientIp
ORDER BY blocked_count DESC
LIMIT 50
"
--query-execution-context Database=waf_logs_db
--result-configuration OutputLocation=s3://my-waf-logs-bucket/athena-results/
--region eu-west-1
CloudWatch Alarmları ile Proaktif İzleme
WAF metrikleri otomatik olarak CloudWatch’a gönderilir. Ani blok artışlarında alarm almak için:
# Yüksek block oranı alarmı
aws cloudwatch put-metric-alarm
--alarm-name "WAF-HighBlockRate"
--alarm-description "WAF blok orani beklenenden yuksek"
--namespace AWS/WAFV2
--metric-name BlockedRequests
--dimensions Name=WebACL,Value=production-web-acl Name=Region,Value=eu-west-1 Name=Rule,Value=ALL
--statistic Sum
--period 300
--threshold 1000
--comparison-operator GreaterThanThreshold
--evaluation-periods 2
--alarm-actions "arn:aws:sns:eu-west-1:123456789012:security-alerts"
--treat-missing-data notBreaching
--region eu-west-1
Bu alarm 5 dakikada 1000’den fazla blok olduğunda SNS üzerinden bildirim gönderir. SNS’i PagerDuty veya Slack’e bağlayabilirsin.
Maliyet Optimizasyonu
AWS WAF’ın maliyeti şu bileşenlerden oluşur:
- Web ACL başına: Aylık 5 USD
- Kural başına: Aylık 1 USD
- 1 milyon istek başına: 0.60 USD
- Bot Control managed rule grubu: 10 USD/ay + 1 USD/milyon istek
Orta ölçekli bir e-ticaret sitesi için aylık WAF maliyeti 50-200 USD arasında değişebilir. Bu maliyeti optimize etmek için birkaç strateji var.
Kural sayısını azalt: Gereksiz kuralları kaldır. Her kural 1 USD/ay demek. Managed rule grupları tek bir kural sayılır, içindeki onlarca kuralı tek fiyata alırsın.
Count modunu akıllıca kullan: Yeni kural denerken önce Count modunda çalıştır. Bu mod için de ücretlendirilirsin, test bitti mi Block’a geç veya kaldır.
Scope-down statement kullan: Rate-based kuralları tüm trafik yerine sadece kritik endpoint’lere uygula. Bu hem cost hem de false positive açısından önemli.
CloudFront + WAF kombinasyonu: WAF’ı doğrudan ALB’ye değil CloudFront’a bağlarsan, edge location’larda filtreleme yaparsın. Kötü trafik backend’e hiç ulaşmaz, bu da EC2/ALB maliyetlerini düşürür.
# WAF'ı ALB'ye bağlama
aws wafv2 associate-web-acl
--web-acl-arn "arn:aws:wafv2:eu-west-1:123456789012:regional/webacl/production-web-acl/your-id"
--resource-arn "arn:aws:elasticloadbalancing:eu-west-1:123456789012:loadbalancer/app/prod-alb/your-alb-id"
--region eu-west-1
# Mevcut ilişkilendirmeleri kontrol et
aws wafv2 list-resources-for-web-acl
--web-acl-arn "arn:aws:wafv2:eu-west-1:123456789012:regional/webacl/production-web-acl/your-id"
--region eu-west-1
False Positive Yönetimi
En büyük sorunlardan biri meşru trafiğin bloklanması. Özellikle yeni WAF kurarken veya yeni kural eklerken bu risk yüksek. False positive yönetimi için sistematik bir yaklaşım şart:
Aşama 1: Yeni kuralı Count modunda en az 72 saat çalıştır. Aşama 2: CloudWatch ve Athena loglarını incele. Engellenen URL’lere, User-Agent’lara ve IP’lere bak. Aşama 3: Meşru trafiği temsil eden pattern’leri belirle. Aşama 4: Gerekirse kural scope’unu daralt veya exception ekle. Aşama 5: Block moduna al ve ilk 24 saati yakın izle.
Bir müşteride yaşanan durumu örnek vereyim: AWSManagedRulesCommonRuleSet devreye aldıktan sonra ödeme sayfasındaki 3D Secure redirect istekleri bloklanmaya başladı. Log analizi yapınca sorunun GenericRFI_QUERYARGUMENTS kuralından geldiğini gördük. Ödeme sağlayıcısının callback URL’indeki parametre bu kuralı tetikliyordu. Çözüm olarak o spesifik kuralı exclude ettik, kural grubunu tamamen kaldırmadık.
Terraform ile WAF’ı Infrastructure as Code Olarak Yönetmek
Production ortamında WAF konfigürasyonunu Terraform ile yönetmek büyük kolaylık sağlar:
# Terraform WAF modülü için temel yapı
cat > waf.tf << 'EOF'
resource "aws_wafv2_web_acl" "main" {
name = "production-web-acl"
scope = "REGIONAL"
default_action {
allow {}
}
rule {
name = "AWSManagedRulesCommonRuleSet"
priority = 10
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesCommonRuleSet"
vendor_name = "AWS"
excluded_rule {
name = "SizeRestrictions_BODY"
}
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "CommonRuleSet"
sampled_requests_enabled = true
}
}
rule {
name = "RateLimitAPI"
priority = 5
action {
block {}
}
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "RateLimitAPI"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "ProductionWebACL"
sampled_requests_enabled = true
}
tags = {
Environment = "production"
ManagedBy = "terraform"
}
}
resource "aws_wafv2_web_acl_association" "alb" {
resource_arn = aws_lb.main.arn
web_acl_arn = aws_wafv2_web_acl.main.arn
}
EOF
# Terraform planı çalıştır
terraform init
terraform plan -out=waf.tfplan
terraform apply waf.tfplan
Terraform ile yönetmenin bir diğer avantajı: değişiklikleri Git’e commit ettiğinde WAF konfigürasyon geçmişine sahip olursun. “Bu kural ne zaman eklendi, kim ekledi” sorularına anında cevap bulabilirsin.
Sonuç
AWS WAF, doğru yapılandırıldığında web uygulamaları için ciddi bir güvenlik katmanı sunuyor. Ancak “kur ve unut” yaklaşımıyla yaklaşılmamalı. Birkaç kritik noktayı vurgulamak istiyorum:
Önce Count, sonra Block: Yeni kuralları asla direkt Block modunda devreye alma. Her zaman Count ile başla, logları analiz et, sonra Block’a geç.
Logging olmadan WAF kördür: Firehose + S3 + Athena üçlüsünü mutlaka kur. Loglar olmadan neyin bloklandığını, neyin geçtiğini göremezsin.
Maliyet takibi ihmal edilmez: WAF maliyetlerini AWS Cost Explorer’dan düzenli takip et. Yüksek trafikli dönemlerde maliyet hızla artabilir.
Managed rules başlangıç noktası: AWS’nin sunduğu managed rule grupları iyi bir başlangıç noktası ama her uygulamanın kendine özgü ihtiyaçları var. Zaman içinde kendi custom kurallarını geliştirmen gerekecek.
Terraform ile yönet: Production WAF konfigürasyonunu kesinlikle IaC olarak yönet. Console üzerinden yapılan değişiklikler takip edilemez, geri alınamaz ve tekrarlanamaz.
WAF bir sihirli değnek değil, kapsamlı bir uygulama güvenliği stratejisinin parçası. Input validasyon, güvenli kodlama pratikleri ve düzenli güvenlik testleriyle birleştirildiğinde gerçek anlamda etkili olur.
