Mert Özen Her Satırda Daha İleri
DevOps Domain, DNS ve CDN — #07

Edge'de Güvenlik: WAF, DDoS Koruması, Rate Limiting, Bot Yönetimi ve Origin'i Kilitlemek

Mert Özen 14 Kas 2026 14 dk 2 görüntülenme
Edge'de Güvenlik: WAF, DDoS Koruması, Rate Limiting, Bot Yönetimi ve Origin'i Kilitlemek

Edge'deki WAF, DDoS koruması, rate limit ve bot kuralları yalnızca edge'den geçen trafiği görür; origin'in IP'si sızarsa hepsi atlanır, bu yüzden origin yalnızca CDN'den gelen bağlantıları kabul etmeli. Nginx'li bir edge'de login rate limit'inin saldırıyı origin'e ulaşmadan durdurduğunu, ASP.NET Core rate limiter'ında forwarded header sırasının müşterileri nasıl koruduğunu ve IP allowlist'in neden Authenticated Origin Pulls, tunnel veya X-Azure-FDID ile tamamlanması gerektiğini görüyoruz.

Sürüm notu: Bu yazıdaki örnekler .NET 10 (ASP.NET Core rate limiter), xUnit 2.9 ve Microsoft.AspNetCore.Mvc.Testing 10.0.15 ile, edge rolünde Nginx 1.30.6 ile Docker 29 üzerinde denenmiştir; Cloudflare ve Azure Front Door özellikleri ve plan sınırları 14 Kasım 2026 tarihli resmi dokümanlardan aktarılmıştır, bir Cloudflare veya Azure hesabında çalıştırılmamıştır.

Önce Tahmin Et

Sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) Cloudflare'in arkasında: WAF (web uygulaması güvenlik duvarı) açık, /api/auth/login için bir rate limiting kuralı var, Bot Fight Mode açık. Bir gece login endpoint'ine dakikada binlerce deneme geliyor ve Cloudflare'in panelinde hiçbiri görünmüyor. Saldırgan, Bookstore'un Cloudflare'e geçmeden önceki A kaydını bir geçmiş DNS veritabanında bulmuş ve origin'e doğrudan bağlanıyor.

Tahmin et: Edge'deki kurallardan hangisi bu saldırganı durdurur? Origin'deki ASP.NET Core rate limiter'ı durdurur mu, durdurursa bu sırada gerçek müşteriler ne yaşar? Bu yazı edge'deki güvenlik katmanlarını savunma tarafından ele alıyor ve bu sorunun cevabıyla bitiyor: saldırı tekniğini değil, tespit ve önlemeyi anlatıyoruz.

Katmanlar: Ne, Nerede Durur?

Edge güvenliği tek bir ürün değil, sırayla çalışan katmanlardan oluşur. Bir isteğin karşılaştığı sıra kabaca şöyle:

KatmanNeye karşıBookstore'daki karşılığı
Ağ seviyesi DDoS (L3/L4)Bant genişliğini veya bağlantı tablolarını dolduran trafikCloudflare'in anycast ağı, bütün planlarda
HTTP DDoS (L7)Geçerli görünen ama aşırı hacimli HTTP istekleriCloudflare'in HTTP DDoS managed ruleset'i
WAFBilinen saldırı imzaları, uygulamaya özel kurallarManaged ruleset'ler ve custom rule'lar
Rate limitingTek bir kaynaktan aşırı istek/api/auth/login ve sipariş endpoint'leri
Bot yönetimiOtomatik araçlarBot Fight Mode, gerektiğinde challenge
Origin kilidiEdge'i atlayan her şeyYalnızca Cloudflare'den gelen bağlantılar

Son satır diğerlerinin hepsinin ön koşulu. Edge'deki her kural, trafiğin edge'den geçtiği varsayımına dayanır. Önce Tahmin Et'in cevabı da bu: edge'deki hiçbir kural, edge'e hiç uğramayan bir isteği göremez. Önce diğer katmanlara bakıp origin kilidini sona bırakacağız, çünkü yazının asıl dersi orada.

WAF: Managed Ruleset'ler, Custom Rule'lar ve Önce Gözlemlemek

WAF, istekleri kurallara göre inceleyip engelleyen ya da challenge'a gönderen katman. Cloudflare'de iki tür kural var. Managed ruleset'ler Cloudflare'in yazıp güncellediği kural setleri: bilinen CVE'ler (yayımlanmış güvenlik açıklarının kayıt numaraları), SQL injection ve XSS (siteler arası script çalıştırma) imzaları. Custom rule'lar ise senin uygulamana özel kurallar: "admin paneline yalnızca şirketin IP'lerinden" veya "/api/'ye POST yalnızca application/json ile" gibi.

Plan sınırları sık değişiyor; Cloudflare'in dokümanında bugün yazan şu: Free Managed Ruleset bütün planlarda açık. Cloudflare Managed Ruleset ve OWASP (web güvenliği üzerine çalışan açık topluluk) Core Ruleset'in Cloudflare uyarlaması Pro ve üstü planlarda. Exposed Credentials Check deprecated sayılıyor, yerine leaked credentials detection öneriliyor. Bookstore kullanıcı login'i barındırdığı için Pro planın kural setleri, özellikle OWASP Core Ruleset, fiyatına değer. OWASP Top 10'un uygulama tarafındaki karşılıkları Web Güvenliği (OWASP Top 10) serisinde; WAF bu açıkları kapatmaz, yalnızca istismarı zorlaştırır.

Yeni bir kuralı doğrudan "Block" ile açmak, false positive'leri (meşru isteklerin yanlışlıkla engellenmesini) production'da keşfetmek demek. Doğru sıra: önce gözlemle, sonra engelle. Cloudflare'de bir kuralı yalnızca kayıt tutacak şekilde çalıştıran "Log" aksiyonu yalnızca Enterprise planlarda var. Diğer planlarda iki yol kalıyor. Birincisi, kuralı önce dar bir kapsamla (yalnızca bir path veya bir test host'u) açıp Security Events ekranını izlemek. İkincisi, Block yerine Managed Challenge ile başlamak: meşru bir kullanıcı challenge'ı geçer, bot geçemez; olaylar yine Security Events'te görünür. Bookstore'da en olası false positive kaynakları belli: yönetim panelinde kitap açıklaması olarak girilen HTML ve kurumsal portalda yüklenen CSV (virgülle ayrılmış veri) dosyaları. Bunlar için kuralı tamamen kapatmak yerine o path'e özgü bir skip/exception yaz ve sebebini kuralın açıklamasına not et.

Rate Limiting: Edge ve Origin Katman Katman

Login endpoint'ine yönelik bir parola deneme saldırısının iki yüzü var: tek bir kaynaktan yüksek hacim ve çok sayıda kaynaktan düşük hacim. Edge birincisini ucuza durdurur; ikincisi için uygulamanın kendi kuralları gerekir. Cloudflare'in rate limiting rule'ları plana göre çok farklı: dokümana göre Free planda 1 kural, yalnızca IP'ye göre sayım, 10 saniyelik sayım süresi ve 10 saniyelik engelleme; Pro'da 2 kural ve en fazla 1 dakikalık süre; Business'ta 5 kural ve IP'nin yanında NAT (birçok cihazın tek bir public IP'yi paylaşması) arkasındaki kullanıcıları ayırabilen sayım; header, cookie veya JSON alanına göre sayım ise Enterprise'da. Bookstore'un tek kuralı login'e: aynı IP'den 10 saniyede 5'ten fazla POST /api/auth/login gelirse engelle.

Edge'deki davranışı laboratuvarda Nginx'in limit_req'iyle canlandırdım. Origin bu kez Kestrel'de HTTPS ile, self-signed bir certificate'la çalışıyor; edge ona Cloudflare'in Full moduna karşılık gelecek şekilde HTTPS ile bağlanıyor:

# login endpoint'i için edge tarafında rate limit (CDN'deki rate limiting kuralının yerine)
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

upstream origin_tls {
    server host.docker.internal:5443;
}

server {
    listen 8082;
    server_name bookstore.example;
    proxy_set_header Host $host;

    location = /api/auth/login {
        limit_req zone=login burst=5 nodelay;
        limit_req_status 429;
        proxy_pass https://origin_tls;
    }

    location / {
        proxy_pass https://origin_tls;
    }
}
$ for i in $(seq 1 8); do curl -s -o /dev/null -D /tmp/e.hdr -X POST -H "Host: bookstore.example" \
    -H "Content-Type: application/json" -d '{"email":"ada@example.com","password":"wrong"}' \
    http://127.0.0.1:8082/api/auth/login; echo "$i: $(head -1 /tmp/e.hdr | tr -d '\r') $(grep -i '^x-origin-request' /tmp/e.hdr | tr -d '\r')"; done
1: HTTP/1.1 401 Unauthorized X-Origin-Request: 2
2: HTTP/1.1 401 Unauthorized X-Origin-Request: 3
3: HTTP/1.1 401 Unauthorized X-Origin-Request: 4
4: HTTP/1.1 401 Unauthorized X-Origin-Request: 5
5: HTTP/1.1 401 Unauthorized X-Origin-Request: 6
6: HTTP/1.1 401 Unauthorized X-Origin-Request: 7
7: HTTP/1.1 429 Too Many Requests
8: HTTP/1.1 429 Too Many Requests 

İlk altı istek (bir hak ve beşlik burst) origin'e ulaştı ve yanlış parola için 401 aldı. Yedinci ve sekizinci istekte X-Origin-Request yok: 429'u edge verdi, origin bu istekleri hiç görmedi. Edge limitinin asıl değeri bu. Saldırının maliyeti origin'in CPU'sunda, veritabanında ve parola hash'lemede değil, edge'de kalıyor.

Origin'deki ikinci katman, ASP.NET Core'un rate limiter'ı. Algoritmaları, partition key seçimini ve "IP başına limit neden yetmez" konusunu ASP.NET Core Güvenliği serisinin "Rate Limiting Derinlemesine" yazısında anlattık. Burada CDN (içerik dağıtım ağı) arkasında olmanın getirdiği tek bir ayrıntıya bakıyoruz:

using System.Threading.RateLimiting;
using Microsoft.AspNetCore.RateLimiting;

namespace Bookstore.Api;

public static class EdgeProtection
{
    public const string LoginPolicy = "login";

    // CDN'deki limitin arkasındaki ikinci katman: forwarded header'lar uygulandıktan sonra, client IP başına.
    public static IServiceCollection AddLoginRateLimit(this IServiceCollection services) =>
        services.AddRateLimiter(options =>
        {
            options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
            options.AddPolicy(LoginPolicy, context => RateLimitPartition.GetFixedWindowLimiter(
                context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
                _ => new FixedWindowRateLimiterOptions { PermitLimit = 10, Window = TimeSpan.FromMinutes(1) }));
        });

    // Azure Front Door: kendi profilimizden gelmeyen istekleri reddet.
    public static IApplicationBuilder RequireFrontDoorId(this IApplicationBuilder app, string? frontDoorId) =>
        frontDoorId is null
            ? app
            : app.Use(async (context, next) =>
            {
                if (context.Request.Headers["X-Azure-FDID"] != frontDoorId)
                {
                    context.Response.StatusCode = StatusCodes.Status403Forbidden;
                    return;
                }

                await next();
            });
}
builder.Services.AddLoginRateLimit();
var app = builder.Build();

app.UseForwardedHeaders();
app.RequireFrontDoorId(app.Configuration["FrontDoor:Id"]);
app.UseHttpsRedirection();
app.UseRateLimiter();

// ...

api.MapPost("/auth/login", (LoginRequest login) =>
    // yalnızca laboratuvar: gerçek uygulama parolayı ASP.NET Core Identity ile kontrol eder
    login.Password == "correct horse" ? Results.Ok() : Results.Unauthorized())
    .RequireRateLimiting(EdgeProtection.LoginPolicy);

Partition key Connection.RemoteIpAddress. Middleware sırası burada kritik: UseForwardedHeaders, UseRateLimiter'dan önce çalışmalı. Aksi hâlde Cloudflare arkasındaki bütün kullanıcılar birkaç Cloudflare edge IP'sini paylaşır ve tek bir saldırgan o edge'den gelen herkesin login hakkını tüketir. Bunu, bütün isteklerin aynı Cloudflare edge'inden geldiği bir testle doğruladım:

using System.Net;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;

namespace Bookstore.Api.Tests;

public class EdgeProtectionTests(WebApplicationFactory<Program> factory) : IClassFixture<WebApplicationFactory<Program>>
{
    private static readonly byte[] WrongPassword = Encoding.UTF8.GetBytes("""{"email":"ada@example.com","password":"wrong"}""");

    private static Task<HttpContext> Login(TestServer server, string clientIp) =>
        server.SendAsync(c =>
        {
            c.Request.Method = "POST";
            c.Request.Scheme = "http";
            c.Request.Host = new HostString("bookstore.example");
            c.Request.Path = "/api/auth/login";
            c.Request.ContentType = "application/json";
            c.Request.ContentLength = WrongPassword.Length;
            c.Request.Body = new MemoryStream(WrongPassword);
            c.Features.Set<IHttpRequestBodyDetectionFeature>(new RequestHasBody());
            c.Connection.RemoteIpAddress = IPAddress.Parse("173.245.48.10");  // bütün istekler aynı Cloudflare edge'inden geliyor
            c.Request.Headers["CF-Connecting-IP"] = clientIp;
            c.Request.Headers["X-Forwarded-Proto"] = "https";
        });

    [Fact]
    public async Task The_login_limit_is_per_visitor_not_per_edge()
    {
        var server = factory.Server;
        var attacker = new List<int>();
        for (var i = 0; i < 11; i++)
        {
            attacker.Add((await Login(server, "198.51.100.66")).Response.StatusCode);
        }

        var customer = (await Login(server, "198.51.100.7")).Response.StatusCode;

        Assert.Equal([.. Enumerable.Repeat(401, 10), 429], attacker);
        Assert.Equal(401, customer);  // parola yanlış, ama başkasının denemeleri yüzünden kilitlenmedi
    }

    [Fact]
    public async Task Front_Door_id_is_enforced_when_configured()
    {
        var server = factory.WithWebHostBuilder(b => b.UseSetting("FrontDoor:Id", "8f4b1c2e-0000-4000-8000-000000000001")).Server;

        var withoutId = await server.SendAsync(c => c.Request.Path = "/api/books");
        var withId = await server.SendAsync(c =>
        {
            c.Request.Path = "/api/books";
            c.Request.Headers["X-Azure-FDID"] = "8f4b1c2e-0000-4000-8000-000000000001";
        });

        Assert.Equal(403, withoutId.Response.StatusCode);
        Assert.NotEqual(403, withId.Response.StatusCode);
    }
}

// TestServer'a elle kurulan bu isteğin bir gövdesi olduğunu söyler
file sealed class RequestHasBody : IHttpRequestBodyDetectionFeature
{
    public bool CanHaveBody => true;
}
$ dotnet test --logger "console;verbosity=normal"
  Passed Bookstore.Api.Tests.ForwardedHeadersTests.A_Cloudflare_edge_is_trusted [177 ms]
  Passed Bookstore.Api.Tests.ForwardedHeadersTests.Anyone_else_is_not_trusted [1 ms]
  Passed Bookstore.Api.Tests.EdgeProtectionTests.The_login_limit_is_per_visitor_not_per_edge [182 ms]
  Passed Bookstore.Api.Tests.EdgeProtectionTests.Front_Door_id_is_enforced_when_configured [43 ms]
Total tests: 4
     Passed: 4
 Total time: 0.5040 Seconds

Saldırgan onuncu denemeden sonra 429 alıyor; aynı edge'den gelen müşteri ise kendi hakkıyla 401 alıyor, yani kilitlenmemiş. Origin'e edge'i atlayarak doğrudan gidildiğinde de bu katman çalışıyor:

$ for i in $(seq 1 11); do code=$(curl -sk -o /dev/null -w "%{http_code}" -X POST -H "Content-Type: application/json" \
    -d '{"email":"ada@example.com","password":"wrong"}' https://127.0.0.1:5443/api/auth/login); printf "%s " "$code"; done; echo
401 401 401 401 401 401 401 401 401 401 429

İki katmanın limitleri bilinçli olarak farklı. Edge sıkı ve ucuz, origin daha gevşek ve son savunma hattı. Sipariş oluşturma (POST /api/orders) için de aynı mantık geçerli, ama limit daha yüksek tutulur: kurumsal portaldan toplu sipariş veren Nevin Hanım'ın okulu, tek bir NAT IP'sinin arkasında onlarca kullanıcıyla gelir. Burada IP başına sert bir edge limiti, gerçek bir müşteri grubunu engeller.

DDoS, Bot Fight Mode ve Challenge'ların UX Maliyeti

DDoS (dağıtık hizmet engelleme) saldırısı iki seviyede gelir. Ağ seviyesinde (L3/L4) amaç bant genişliğini veya sunucunun bağlantı tablosunu doldurmaktır; bu trafiği uygulama hiç görmez ve tek savunma, saldırıyı origin'e ulaşmadan emecek kadar büyük bir ağdır. HTTP seviyesinde (L7) istekler geçerli görünür ve pahalı endpoint'leri hedefler: arama, sepet hesaplama, PDF üretimi. Cloudflare'in dokümanına göre L3'ten L7'ye ölçümsüz (unmetered) DDoS koruması bütün planlarda var. Bu, Bookstore'un ayrıca bir DDoS ürünü almasına gerek olmadığı anlamına gelir, ama origin kilitli değilse bu koruma da devre dışıdır.

Bot Fight Mode, Cloudflare'in Free planda da sunduğu, bilinen bot desenlerine uyan trafiğe pahalı challenge'lar gönderen bir özellik. Dokümanda yazan sınırları önemli: bütün domain için çalışır, path bazında kapatılamaz ve custom rule'larla atlanamaz, çünkü WAF'ın kural motoru dışında çalışır. API ve mobil uygulama trafiğini de challenge'a sokabilir. Bookstore'un Angular uygulaması tarayıcıda çalıştığı için çoğu durumda sorun çıkmaz. Ama kurumsal müşterilerin entegrasyonları veya bir izleme aracı /api/'yi çağırıyorsa engellenebilir. Pro ve üstü planlardaki Super Bot Fight Mode WAF'ın kural motorunda çalışır ve skip kurallarıyla belirli trafiğe istisna tanır. API'si dışarıya açık bir sistemde bu fark belirleyici.

Turnstile gibi challenge'lar CAPTCHA'nın (insan olduğunu kanıtlamak için çözülen test) yerini almak için tasarlandı ve çoğu kullanıcıda görünmez kalıyor. Yine de her challenge bir bekleme, bazen bir tıklama ve ekran okuyucu kullananlar için ek bir engel demek. Kural: challenge'ı her sayfaya değil, riskli eylemlere ve şüpheli sinyallere koy. Login formunda birkaç başarısız denemeden sonra, kayıt formunda ve kampanya kodu girişinde mantıklı; katalog sayfasında değil. Erişilebilirlik tarafını Accessibility (a11y) serisinde ele alıyoruz.

Origin'i Kilitlemek

Önce Tahmin Et'teki saldırgana dönelim. Origin'in IP'si altıncı yazıda saydığımız yollardan biriyle sızdı. Edge'deki WAF, rate limit ve bot kurallarının hiçbiri bu trafiği görmüyor. Tek cevap, origin'in yalnızca CDN'den gelen bağlantıları kabul etmesi. Bunun dört yolu var ve birbirini tamamlıyorlar.

IP allowlist: Origin'in önündeki firewall'da (bulutta network security group, sunucuda Nginx veya işletim sisteminin firewall'u) yalnızca Cloudflare'in aralıklarına izin ver. Altıncı yazıdaki cloudflare-ips.txt'den Nginx kuralı üreten bir script:

#!/bin/sh
# cloudflare-ips.txt'yi nginx allow kurallarına çevirir; geri kalan her şey reddedilir.
# Kullanım: make-nginx-allowlist.sh cloudflare-ips.txt > cloudflare-allow.conf
echo "# generated from Cloudflare's published ranges, do not edit"
while read -r range; do
    [ -n "$range" ] && echo "allow $range;"
done < "$1"
echo "deny all;"
# origin tarafındaki kilit: yalnızca Cloudflare'in aralıkları bağlanabilir
server {
    listen 8090;
    server_name bookstore.example;
    include /etc/nginx/cloudflare-allow.conf;

    location / {
        proxy_pass https://origin_tls;
    }
}
$ ./make-nginx-allowlist.sh cloudflare-ips.txt > cloudflare-allow.conf
$ head -3 cloudflare-allow.conf; tail -2 cloudflare-allow.conf
# generated from Cloudflare's published ranges, do not edit
allow 173.245.48.0/20;
allow 103.21.244.0/22;
allow 2c0f:f248::/32;
deny all;
$ curl -s -o /dev/null -w "%{http_code}\n" -H "Host: bookstore.example" http://127.0.0.1:8090/api/books
403

Cloudflare'den gelmeyen istek 403 alıyor. Ama IP allowlist tek başına yetmez, çünkü Cloudflare'in IP'leri herkesin. Başka bir Cloudflare müşterisi kendi zone'unda bir kaydı senin origin IP'ne yönlendirirse, onun trafiği de Cloudflare'in IP'lerinden gelir ve allowlist'ten geçer; üstelik senin WAF ve rate limit kurallarından değil, onunkilerden geçmiş olur. Azure Front Door'un dokümanı aynı uyarıyı Front Door için yapıyor: aynı IP'leri diğer Azure müşterileri de kullanıyor.

Authenticated Origin Pulls: Cloudflare, origin'e bağlanırken bir client certificate sunar ve origin bu certificate'ı doğrulamadan bağlantıyı kabul etmez. Bu, SSL/TLS Certificate'ları ve HTTPS serisinin mTLS yazısında anlattığımız mutual TLS'in (iki tarafın da certificate sunduğu şifreli bağlantı) ta kendisi. Cloudflare'in dokümanına göre üç seviyesi var. Global seviye bütün hesapların paylaştığı bir Cloudflare certificate'ı kullanır ve yalnızca "istek Cloudflare'den geliyor" der, "senin hesabından geliyor" demez. Zone seviyesi ve hostname seviyesi ise senin yüklediğin certificate'la çalışır ve hesabına özeldir. Bu yüzden yukarıdaki açığı kapatan, kendi certificate'ınla zone veya hostname seviyesi. Authenticated Origin Pulls yalnızca Full ve Full (strict) modlarında çalışır.

Tunnel: Origin'de çalışan cloudflared ajanı Cloudflare'e dışarı doğru bir bağlantı açar ve trafik bu bağlantıdan gelir. Origin'in internete açık hiçbir portu olmaz, firewall'da tek bir inbound kural bile gerekmez. Sızan bir IP'nin hiçbir değeri kalmaz. Yeni kurulumlarda en temiz seçenek bu.

Azure Front Door: Microsoft'un önerisi iki adımı birlikte uygulamak: origin'in network security group'unda yalnızca AzureFrontDoor.Backend service tag'ine izin vermek ve uygulamada her istekteki X-Azure-FDID header'ının kendi profilinin kimliğiyle eşleştiğini kontrol etmek. App Service'te ikisini de access restrictions ile koda dokunmadan yapabilirsin. Kendi kodunda yapmak istersen yukarıdaki RequireFrontDoorId bunu yapıyor ve test, kimlik olmadan gelen isteğin 403 aldığını gösteriyor. Premium katmanda Private Link ile origin'i internetten tamamen çıkarmak da mümkün.

Edge Log'larını İzlemek

Engellenen saldırı da bir sinyaldir. Cloudflare'de Security Events ekranı WAF, rate limit ve bot kararlarını tek tek gösterir. Ama asıl değer bu olayları uygulama log'larıyla aynı yerde görmekte. Logpush, edge log'larını bir depolama servisine veya SIEM'e (güvenlik olaylarını toplayıp ilişkilendiren sistem) gönderir; Cloudflare'in dokümanına göre bütün planlarda var, ama hangi veri setlerinin açık olduğu kullandığın ürünlere bağlı. Azure Front Door'da aynı rolü diagnostic log'lar ve Log Analytics üstlenir.

İki pratik öneri. Birincisi, origin'in log'una Cloudflare'in her istekte gönderdiği CF-Ray header'ını yaz. Bir müşteri "engellendim" dediğinde edge'deki kararı origin'deki isteğe bu kimlikle bağlarsın. İkincisi, alarmları sayıya değil değişime göre kur. "Login'de 429 sayısı son bir saatte normalin on katı" veya "WAF'ın engellediği isteklerin yarısı tek bir ülkeden" gibi sinyaller, Observability serisinde kuracağımız alarm altyapısının ilk kullanıcıları.

Üretimde Dikkat

Origin kilidini doğrula, varsay değil. Origin'in IP'sine dışarıdan, CDN'i atlayarak bir istek atan ve bağlantının reddedildiğini kontrol eden bir job çalıştır. Bir firewall kuralının bir altyapı değişikliğinde sessizce silinmesi sık rastlanan bir durum.

Kuralların sahibi ve sebebi olsun. Her custom rule'un ve her istisnanın açıklama alanında neden eklendiği ve kimin eklediği yazsın. Altı ay sonra "bu skip kuralı neden var?" sorusunun cevabı yoksa, kimse onu kaldırmaya cesaret edemez ve açık orada kalır.

Plan sınırlarını mimari karara dahil et. Free planın tek rate limiting kuralı ve 10 saniyelik penceresi, login ile sipariş endpoint'ini aynı anda korumaya yetmez. İhtiyacın Pro'nun iki kuralını da aşıyorsa, origin'deki limiter'ın yükü artar. Plan yükseltmek bazen en ucuz güvenlik önlemi.

Acil durum planını önceden yaz. Bir saldırı sırasında atılacak adımlar belli olsun: Cloudflare'in "Under Attack" modu, belirli ülkeler veya ASN'ler (bir ağ operatörünün internet üzerindeki kimlik numarası) için geçici challenge kuralları, origin'de pahalı endpoint'leri kapatan bir feature flag. Bunları saldırı anında ilk kez denemek yerine bir tatbikatta dene.

Sık Düşülen Tuzaklar

Origin'i açık bırakmak: Önce Tahmin Et'teki durum. CDN'in bütün güvenlik özellikleri, origin'e doğrudan ulaşılabildiği sürece isteğe bağlıdır.

Yalnızca IP allowlist'e güvenmek: Cloudflare ve Front Door'un IP'lerini başka müşteriler de kullanıyor. Allowlist'i Authenticated Origin Pulls (kendi certificate'ınla), X-Azure-FDID kontrolü veya bir tunnel ile tamamla.

Origin'deki rate limiter'ı forwarded header'lardan önce çalıştırmak: Bütün kullanıcılar birkaç edge IP'sini paylaşır ve tek bir saldırgan herkesi kilitler. UseForwardedHeaders her zaman önce gelir.

Yeni WAF kuralını doğrudan Block ile açmak: False positive'ler müşteri şikâyetiyle ortaya çıkar. Dar bir kapsamla veya Managed Challenge ile başla, Security Events'i izle, sonra sıkılaştır.

Bot Fight Mode'u API'nin önünde unutmak: Kurumsal entegrasyonlar ve izleme araçları challenge'ı çözemez. API'si dışarıya açık bir sistemde, istisna tanımlanabilen Super Bot Fight Mode'u değerlendir.

Küçük Bir Deneme

★☆☆ Laboratuvardaki edge'in login limitini rate=5r/m'den rate=1r/s'e çevir ve aynı döngüyü tekrarla. Kaç istek origin'e ulaşıyor? burst değerinin rolü ne?

★★☆ EdgeProtection'a POST /api/orders için ikinci bir policy ekle: IP başına dakikada 30 istek. Aynı kurumdan (aynı IP'den) gelen 40 siparişlik bir toplu işlemde ne olur? Bu senaryoda partition key'i IP yerine giriş yapmış kullanıcının kimliği yapmak neyi değiştirir?

★★★ Origin'in Kestrel'ini client certificate isteyecek şekilde yapılandır ve laboratuvardaki edge'e proxy_ssl_certificate ile bir client certificate ver. Certificate'sız bağlantının reddedildiğini, certificate'lı edge'in geçtiğini doğrula. Bu kurulumun Cloudflare'deki karşılığı Authenticated Origin Pulls'un hangi seviyesi?

Seri burada bitiyor. Bookstore'un domain'ini aldık ve kaybetmemek için önlemlerimizi kurduk, web, API ve mail için DNS kayıtlarını yazdık, DNS değişikliklerini kesintisiz yapmayı ve DNSSEC'i (DNS cevaplarını imzalayan uzantı) taşımayı öğrendik, CDN'in cache mantığını kurduk, Cloudflare'e geçtik ve edge'i ve origin'i kilitledik. Bu katmanların her biri bir sonraki adımın temeli: Terraform ile altyapıyı kod olarak yönetmek, Observability ile bu katmanları izlemek ve Cloud Temelleri'nde Azure tarafını kurmak bu seriden devam ediyor.