Test5410 1
Test5410
farkmt2official 1
farkmt2official
Hikaye Ekle

[NODE JS] Express'te Rate Limiting Uygulama

  • Konuyu başlatan Konuyu başlatan Silverhand
  • Başlangıç tarihi Başlangıç tarihi
  • Cevaplar Cevaplar 1
  • Görüntüleme Görüntüleme 12
nodejs.png


[NODE JS] Express'te Rate Limiting Uygulama​


Rate limiting, API'nize belirli bir zaman diliminde yapılabilecek istek sayısını sınırlamaktır. Bu güvenlik ve performans açısından kritik bir önlemdir. Brute force saldırıları, DDoS saldırıları ve API'nin kötüye kullanımını engellemek için rate limiting şarttır.

express-rate-limit paketi bu işi Express'te çok kolay hale getirir. npm install express-rate-limit ile kurarsınız. Varsayılan olarak IP bazlı sınırlama yapar ve sayaçları bellekte tutar. Basit bir yapılandırmayla uygulamanızı koruma altına alabilirsiniz.

Ben bir API projesinde rate limiting eklemeden production'a çıkmıştım. Birisi script yazıp saniyede yüzlerce istek atıyordu. Sunucu aşırı yüklendi ve meşru kullanıcılar hizmet alamaz hale geldi. Rate limiting eklediğimizde sorun anında çözüldü. O günden sonra her API projesinde rate limiting ilk günden var oluyor.

Farklı endpoint'ler için farklı limitler belirleyebilirsiniz. Login endpoint'ine dakikada 5 istek, genel API'ye dakikada 100 istek, public endpoint'lere dakikada 200 istek gibi. Hassas endpoint'lerde daha düşük limitler kullanmak güvenliği artırır.

Production'da rate limit sayaçlarını Redis'te tutmalısınız. Bellekte tutarsanız sunucu restart olduğunda sayaçlar sıfırlanır ve birden fazla sunucu instance'ınız varsa her biri ayrı sayar. rate-limit-redis paketi ile Redis entegrasyonu yapabilirsiniz.

Rate limit aşıldığında 429 Too Many Requests status code'u döndürülür. Response header'larında kalan istek hakkı (X-RateLimit-Remaining) ve sıfırlanma zamanı (X-RateLimit-Reset) bilgisi bulunur. İstemci bu bilgileri kullanarak isteklerini düzenleyebilir.

Sliding window algoritması sabit pencere algoritmasından daha adil sonuçlar verir. Sabit pencerede her dakikanın başında sayaç sıfırlanır ve kullanıcı sınıra yakınken birkaç saniye bekleyip sıfırlanma anında burst yapabilir. Sliding window bunu engeller ve daha düzgün bir istek dağılımı sağlar.

IP bazlı sınırlama her zaman yeterli değildir. Aynı NAT arkasındaki kullanıcılar aynı IP'yi paylaşır ve birisi diğerlerini etkileyebilir. API key veya kullanıcı ID bazlı sınırlama daha adil olabilir. keyGenerator fonksiyonu ile sınırlama anahtarını özelleştirebilirsiniz.

Retry-After header'ı istemciye ne zaman tekrar deneyebileceğini söyler. RFC standartlarına göre 429 yanıtında bu header bulunmalıdır. Bu header saniye cinsinden bir değer veya HTTP tarih formatında bir değer alabilir.

JavaScript:
const express = require('express');
const rateLimit = require('express-rate-limit');
const app = express();

// npm install express-rate-limit

app.use(express.json());

// Proxy arkasinda calisiyorsaniz (Nginx, Cloudflare vb.)
app.set('trust proxy', 1);

// ===== GENEL RATE LIMITER =====

const genelLimiter = rateLimit({{
  windowMs: 15 * 60 * 1000, // 15 dakika
  max: 100,                  // 15 dakikada max 100 istek
  standardHeaders: true,     // X-RateLimit-* header'lari ekle
  legacyHeaders: false,      // X-RateLimit-Limit header'ini ekleme (eski format)
  message: {{
    hata: 'Cok fazla istek gonderdiniz',
    mesaj: 'Lutfen 15 dakika sonra tekrar deneyin',
    limit: 100,
    pencere: '15 dakika',
  }},
  // Ozel anahtar belirleme (IP yerine kullanici ID vb.)
  keyGenerator: (req) => {{
    return req.headers['x-api-key'] || req.ip;
  }},
  // Bazi IP'leri muaf tut
  skip: (req) => {{
    const whitelist = ['127.0.0.1', '::1'];
    return whitelist.includes(req.ip);
  }},
  // Limit asildiginda loglama
  handler: (req, res, next, options) => {{
    console.warn(`Rate limit asildi: ${{req.ip}} - ${{req.method}} ${{req.url}}`);
    res.status(options.statusCode).json(options.message);
  }},
}});

// Tum route'lara uygula
app.use(genelLimiter);

// ===== GIRIS ENDPOINTI ICIN SIKI LIMITER =====

const girisLimiter = rateLimit({{
  windowMs: 15 * 60 * 1000, // 15 dakika
  max: 5,                    // 15 dakikada max 5 deneme
  message: {{
    hata: 'Cok fazla giris denemesi',
    mesaj: 'Hesabiniz gecici olarak kilitlendi. 15 dakika sonra tekrar deneyin.',
  }},
  skipSuccessfulRequests: true, // Basarili girisleri sayma
}});

// ===== API ANAHTAR BAZLI LIMITER =====

function apiKeyLimiter(planLimitleri) {{
  return (req, res, next) => {{
    const apiKey = req.headers['x-api-key'];
    if (!apiKey) {{
      return res.status(401).json({{ hata: 'API anahtari gerekli' }});
    }}

    // Plan bazli limit belirleme (gercekte DB'den cekilir)
    const planlar = {{
      'free-key-123': {{ plan: 'free', limit: 50, pencere: 60 * 60 * 1000 }},
      'pro-key-456': {{ plan: 'pro', limit: 500, pencere: 60 * 60 * 1000 }},
      'enterprise-key-789': {{ plan: 'enterprise', limit: 5000, pencere: 60 * 60 * 1000 }},
    }};

    const planBilgi = planlar[apiKey];
    if (!planBilgi) {{
      return res.status(401).json({{ hata: 'Gecersiz API anahtari' }});
    }}

    // Dinamik rate limiter olustur
    const limiter = rateLimit({{
      windowMs: planBilgi.pencere,
      max: planBilgi.limit,
      keyGenerator: () => apiKey,
      message: {{
        hata: 'API istek limitiniz doldu',
        plan: planBilgi.plan,
        limit: planBilgi.limit,
      }},
    }});

    limiter(req, res, next);
  }};
}}

// ===== ROUTE'LAR =====

// Giris endpointi - siki rate limit
app.post('/api/giris', girisLimiter, (req, res) => {{
  const {{ email, sifre }} = req.body;
  if (email === 'test@test.com' && sifre === '123456') {{
    res.json({{ mesaj: 'Giris basarili', token: 'ornek-token' }});
  }} else {{
    res.status(401).json({{ hata: 'Hatali bilgiler' }});
  }}
}});

// Genel API endpointi
app.get('/api/veriler', (req, res) => {{
  res.json({{
    veriler: [1, 2, 3, 4, 5],
    rateLimitBilgi: {{
      limit: res.getHeader('X-RateLimit-Limit'),
      kalan: res.getHeader('X-RateLimit-Remaining'),
      sifirlama: res.getHeader('X-RateLimit-Reset'),
    }},
  }});
}});

// Durum kontrol endpointi - rate limit'ten muaf
const durumLimiter = rateLimit({{ windowMs: 60000, max: 30 }});
app.get('/api/durum', durumLimiter, (req, res) => {{
  res.json({{ durum: 'aktif', zaman: new Date().toISOString() }});
}});

// Agir islem endpointi - cok dusuk limit
const agirLimiter = rateLimit({{
  windowMs: 60 * 60 * 1000, // 1 saat
  max: 10,
  message: {{ hata: 'Bu islem icin saatlik limit: 10' }},
}});

app.post('/api/rapor-olustur', agirLimiter, (req, res) => {{
  res.json({{ mesaj: 'Rapor olusturuluyor...', tahminiSure: '30 saniye' }});
}});

app.listen(3000, () => {{
  console.log('Rate limiting sunucusu port 3000\'de');
}});

Rate limiting uygulamanızın ilk savunma hattıdır. Doğru konfigüre edilmiş bir rate limiter, sunucunuzu pek çok saldırıdan korur ve tüm kullanıcıların adil şekilde hizmet almasını sağlar. Production'da Redis tabanlı store kullanmayı ve farklı endpoint'ler için farklı limitler belirlemeyi unutmayın.
 
Emeğiniz ve katkınız için teşekkür ederiz!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar! 🎉
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst