İçeriğe geç
Çılgın Yazılım

Siber Güvenlik kod örnekli

Hız Sınırlama (Rate Limiting): Sunucunuzu Kendi Kullanıcılarından Korumak

Kötü niyet gerekmez; tek bir hatalı istemci döngüsü sistemi düşürebilir. Hız sınırlama bu riski sınırlar.

Çılgın Yazılım 3 dk okuma

Hız Sınırlama (Rate Limiting): Sunucunuzu Kendi Kullanıcılarından Korumak
İçindekiler
  1. Üç algoritma, üç farklı karakter
  2. Sabit pencere
  3. Kayan pencere
  4. Jeton kovası
  5. Filtre olarak bağlamak
  6. Anahtar seçimi: en kritik karar
  7. Uç noktalara farklı maliyet verin
  8. Dağıtık ortamda tek sayaç
  9. Sonuç

Hız sınırlama, belirli bir süre içinde bir istemcinin yapabileceği istek sayısını kısıtlamaktır. Genellikle bir güvenlik önlemi olarak anılır, ama üretimde asıl işlevi daha geniştir: hatalı yazılmış bir istemci döngüsü, tekrar tekrar denenen bir mobil uygulama ya da kontrolsüz bir tarama, kötü niyet olmadan da sistemi düşürebilir.

Hız sınırlama algoritmalarının karşılaştırması
Doğru algoritma kadar doğru anahtar seçimi de belirleyicidir.

Üç algoritma, üç farklı karakter

Sabit pencere

En basiti: "dakikada 60 istek". Uygulaması kolaydır, ama pencere sınırında zayıflığı vardır — istemci 59. saniyede 60, 61. saniyede 60 istek atarsa iki saniye içinde 120 istek geçer.

Kayan pencere

Son 60 saniyeye bakar, sınır patlaması olmaz. Daha adildir ama her istek için zaman damgası tutmayı gerektirir.

Jeton kovası

Kova sabit hızda dolar, her istek bir jeton harcar. Kısa süreli ani yüke izin verirken uzun vadeli ortalamayı korur — çoğu API için en dengeli seçimdir.

PHP
final class JetonKovasi
{
    public function __construct(
        private \CodeIgniter\Cache\CacheInterface $cache,
        private int $kapasite = 60,        // kovanın alabileceği en fazla jeton
        private float $doldurmaHizi = 1.0, // saniyede eklenen jeton
    ) {}

    /** @return array{izin:bool, kalan:int, bekle:int} */
    public function tuket(string $anahtar, int $maliyet = 1): array
    {
        $simdi = microtime(true);
        $durum = $this->cache->get($anahtar) ?: ['jeton' => $this->kapasite, 'an' => $simdi];

        // Geçen süre kadar jeton ekle (tavanı aşmadan)
        $gecen = max(0.0, $simdi - $durum['an']);
        $jeton = min($this->kapasite, $durum['jeton'] + $gecen * $this->doldurmaHizi);

        if ($jeton < $maliyet) {
            $bekle = (int) ceil(($maliyet - $jeton) / $this->doldurmaHizi);
            $this->cache->save($anahtar, ['jeton' => $jeton, 'an' => $simdi], 3600);

            return ['izin' => false, 'kalan' => 0, 'bekle' => $bekle];
        }

        $jeton -= $maliyet;
        $this->cache->save($anahtar, ['jeton' => $jeton, 'an' => $simdi], 3600);

        return ['izin' => true, 'kalan' => (int) floor($jeton), 'bekle' => 0];
    }
}

Filtre olarak bağlamak

PHP
class HizSinirFiltresi implements FilterInterface
{
    public function before(RequestInterface $request, $arguments = null)
    {
        $kova = new JetonKovasi(cache(), kapasite: 60, doldurmaHizi: 1.0);

        // Anahtar seçimi: oturum varsa kullanıcı, yoksa IP
        $kimlik  = session()->get('user_id') ?: $request->getIPAddress();
        $sonuc   = $kova->tuket('hiz:' . $kimlik);

        if (! $sonuc['izin']) {
            // 429 + Retry-After: istemcinin ne zaman tekrar deneyeceğini SÖYLEYİN
            return service('response')
                ->setStatusCode(429)
                ->setHeader('Retry-After', (string) $sonuc['bekle'])
                ->setHeader('X-RateLimit-Remaining', '0')
                ->setJSON(['hata' => 'Çok fazla istek. ' . $sonuc['bekle'] . ' saniye sonra tekrar deneyin.']);
        }

        service('response')->setHeader('X-RateLimit-Remaining', (string) $sonuc['kalan']);
    }

    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) {}
}

Anahtar seçimi: en kritik karar

Yalnızca IP'ye göre sınırlamak, aynı kurumsal ağdan çıkan yüzlerce kullanıcıyı tek istemci sayar ve haksız yere engeller. Yalnızca kullanıcıya göre sınırlamak ise oturum açmadan yapılan saldırıları kaçırır. Pratik çözüm katmanlıdır: giriş uçlarında IP + kullanıcı adı birlikte, kimlik doğrulanmış API'de API anahtarı, herkese açık uçlarda IP. Kaba kuvvet saldırılarına katmanlı savunma yazımız bu ayrımı güvenlik tarafından ele alıyor.

Ters vekil (reverse proxy) arkasındaysanız REMOTE_ADDR her zaman vekilin adresidir. Gerçek istemci IP'sini X-Forwarded-For başlığından alırken yalnızca güvendiğiniz vekile güvenin; aksi hâlde saldırgan başlığı uydurup sınırı atlar.

Sınıra takılan istemcilere verdiğiniz geri bildirimin netliği, ekip içi geri bildirim dili kadar önemlidir: belirsiz mesaj her iki tarafta da zaman kaybettirir.

Uç noktalara farklı maliyet verin

Her istek aynı yükü üretmez. Arama veya rapor üretimi gibi pahalı uçlarda maliyeti artırmak, tek bir sınırın hem hafif hem ağır uçları yönetmesini sağlar: $kova->tuket($anahtar, maliyet: 5). Bu, sistemi asıl yoran isteklerin doğru şekilde fiyatlanmasını sağlar ve yavaş uçların tüm sistemi etkilemesini önler.

Yeni sürüme geçerken sayaçların sıfırlanmaması için sayaç deposu dağıtımdan bağımsız olmalıdır; mavi-yeşil dağıtımdaki paylaşılan kaynak kuralı tam da bunu söyler.

Dağıtık ortamda tek sayaç

Birden fazla uygulama sunucunuz varsa sayaç paylaşılmalıdır; dosya tabanlı önbellek her sunucuda ayrı sayar ve gerçek sınır sunucu sayısıyla çarpılır. Redis gibi merkezî bir depo kullanın ve mümkünse okuma-güncelleme işlemini atomik bir betikle yapın. HTTP tarafındaki standart yanıt kodu için MDN 429 belgeleri beklenen davranışı tanımlar.

Sonuç

Hız sınırlama, sistemi kötü niyetli saldırılardan olduğu kadar iyi niyetli hatalardan da korur. Jeton kovası çoğu API için doğru varsayılandır: ani yüke izin verir, ortalamayı sabit tutar. Kurarken üç şeye dikkat edin — anahtarı doğru seçin (IP tek başına yetmez), sınıra takılan istemciye 429 ve Retry-After ile ne yapması gerektiğini söyleyin, dağıtık kurulumda sayacı merkezîleştirin. Bir sonraki üretim yoğunluğunda, sistemi düşüren şeyin bir saldırı değil tek bir hatalı döngü olduğunu görürseniz şaşırmayın; bu sınır tam da onun için vardır.

Beğeniniz benzer içerikleri öne çıkarmamıza yardımcı olur.

Sık sorulan sorular

Hız sınırı değerini nasıl belirlemeliyim?

Tahminle değil, ölçümle. Mevcut trafikte kullanıcı başına dakikalık istek dağılımını çıkarın ve sınırı normal kullanımın belirgin biçimde üzerine koyun. Sınırı önce yalnızca günlüğe yazan "gözlem modunda" çalıştırmak, gerçek kullanıcıları engellemeden kalibrasyon yapmanızı sağlar.

429 yerine isteği yavaşlatmak (throttle) daha mı iyi?

Yavaşlatmak, istemcinin bağlantısını açık tutar ve sunucu kaynağını meşgul eder; yoğun anda durumu kötüleştirir. Net bir 429 ve Retry-After, hem sunucuyu serbest bırakır hem de iyi yazılmış istemcilerin doğru davranmasını sağlar.

Hız sınırlama DDoS saldırısını durdurur mu?

Uygulama seviyesindeki sınırlama, dağıtık ve yüksek hacimli bir saldırıyı tek başına durduramaz — trafik zaten sunucunuza ulaşmıştır. Bu tür saldırılar için ağ katmanında (CDN veya güvenlik duvarı) filtreleme gerekir. Uygulama sınırlaması, tekil istemci kaynaklı aşırı kullanıma karşı etkilidir.

Kimlik doğrulaması olmayan uçlarda ne yapmalı?

IP tabanlı sınırlamayı daha sıkı tutun ve pahalı işlemleri kimlik doğrulaması arkasına alın. Herkese açık kalması gereken uçlarda ise önbelleklemeyi devreye sokmak, sınırlamadan bile daha etkili bir koruma sağlar.

Yazan

Çılgın Yazılım

Ben Evren Çılgın; yazılım geliştirme, web teknolojileri ve sistem tasarımı alanlarında uzmanlaşmış bir geliştiriciyim. Uzun yıllardır hem frontend hem de backend tarafında üretken, ölçeklenebilir ve kullanıcı dostu çözümler üretiyorum.

Hakkımızda Bize ulaşın

Bu konuda bir projeniz mi var?

İhtiyacınızı birkaç cümleyle anlatın; uygun yaklaşımı birlikte belirleyelim.

Projenizi Anlatın

İlgili yazılar

Yorumlar

Henüz yorum yok. Sorunuzu ya da deneyiminizi ilk siz yazın.

Yorum yazın

Yorumunuz onaylandıktan sonra yayınlanır. Ekibimiz gerekirse konuyla ilgili bir yanıt da paylaşır.

Yayınlanmaz; yalnızca gerektiğinde size ulaşmak için.

En az 10 karakter.

Tüm yazılar