emirhanHCL 1
emirhanHCL
kralhakan2009 1
kralhakan2009
Vahsi Uzman 1
Vahsi Uzman
farkmt2official 1
farkmt2official
mannaxxx 1
mannaxxx
Bvural41 1
Bvural41
Agora Metin2 1
Agora Metin2
Hikaye Ekle

[NODE JS] Rate Limiting ile Brute Force Koruması

Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!

nodejs.png


[NODE JS] Rate Limiting ile Brute Force Koruması​


Merhaba, bu konuda rate limiting yani istek sınırlama konusunu ele alacağız. Brute force saldırıları, DDoS girişimleri ve API suistimallerine karşı en temel savunma mekanizmalarından biri. Bir IP adresinden veya kullanıcıdan belirli sürede kaç istek gelebileceğini sınırlıyoruz.

Rate limiting olmadan ne olur? Saldırgan giriş formunuza saniyede yüzlerce deneme yaparak şifre kırmaya çalışabilir. API'nize dakikada binlerce istek atarak sunucunuzu çökertebilir. Veya bir bot tüm ürün bilgilerinizi dakikalar içinde scrape edebilir. Bunların hepsini rate limiting ile engelleyebilirsiniz.

Ben her projemde en az iki katmanlı rate limiting uygularım: genel bir sınır tüm endpoint'ler için, ve hassas endpoint'ler için daha sıkı bir sınır. Login, register, şifre sıfırlama gibi endpoint'lere çok daha düşük limitler koyarım çünkü bunlar brute force'un hedefidir.

Express için express-rate-limit paketi standart çözüm. Basit uygulamalar için yeterli. Ama büyük ölçekli uygulamalarda Redis tabanlı rate limiting kullanmanız gerekir, çünkü birden fazla sunucu instance'ı varsa her biri kendi belleğindeki sayaçları tutar ve toplam limit aşılabilir.

Express Rate Limit Kullanımı​


JavaScript:
const express = require('express');
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const Redis = require('ioredis');

const app = express();
app.use(express.json());

// Genel rate limiter - tum endpointler icin
const genelLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 dakika
    max: 100,                  // 15 dakikada max 100 istek
    standardHeaders: true,     // RateLimit-* headerlari ekle
    legacyHeaders: false,
    message: {
        hata: 'Cok fazla istek gonderdiniz. Lutfen 15 dakika sonra tekrar deneyin.',
        limitResetSuresi: '15 dakika'
    },
    keyGenerator: (req) => {
        // IP bazli sinirla (proxy arkasindaysa X-Forwarded-For kullan)
        return req.ip || req.headers['x-forwarded-for'] || 'unknown';
    },
    skip: (req) => {
        // Healthcheck endpointi limitten muaf
        return req.path === '/health';
    }
});

app.use(genelLimiter);

// Login icin siki limiter
const loginLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 dakika
    max: 5,                    // 15 dakikada max 5 giris denemesi
    message: {
        hata: 'Cok fazla giris denemesi. 15 dakika sonra tekrar deneyin.',
        kalanDeneme: 0
    },
    keyGenerator: (req) => {
        // Hem IP hem kullanici adi bazli
        return req.ip + ':' + (req.body.email || 'unknown');
    }
});

// API icin ayri limiter
const apiLimiter = rateLimit({
    windowMs: 60 * 1000,  // 1 dakika
    max: 30,               // Dakikada 30 istek
    message: { hata: 'API istek limiti asildi.' }
});

// Route'lara uygula
app.post('/api/giris', loginLimiter, (req, res) => {
    // Giris islemi
    res.json({ basarili: true });
});

app.use('/api/', apiLimiter);

// Redis tabanli rate limiting (coklu sunucu icin)
const redis = new Redis({
    host: process.env.REDIS_HOST || 'localhost',
    port: 6379
});

const redisLimiter = rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 100,
    store: new RedisStore({
        sendCommand: (...args) => redis.call(...args)
    })
});

// Kendi rate limiter middleware'imiz (Redis ile)
async function ozelRateLimiter(limit, pencereSaniye) {
    return async (req, res, next) => {
        const anahtar = 'rl:' + req.ip + ':' + req.path;
        const multi = redis.multi();
        multi.incr(anahtar);
        multi.expire(anahtar, pencereSaniye);
        const sonuclar = await multi.exec();
        const istekSayisi = sonuclar[0][1];

        res.setHeader('X-RateLimit-Limit', limit);
        res.setHeader('X-RateLimit-Remaining', Math.max(0, limit - istekSayisi));

        if (istekSayisi > limit) {
            return res.status(429).json({
                hata: 'Istek limiti asildi',
                tekrarDeneme: pencereSaniye + ' saniye sonra'
            });
        }

        next();
    };
}

app.listen(3000);

Gelişmiş Stratejiler​


Basit rate limiting yeterli olmayabilir. Sliding window algoritması daha adil bir dağılım sağlar, fixed window'daki sınır geçişi sorununu çözer. Token bucket algoritması ise burst traffic'e izin verirken ortalama hızı sınırlar, API'ler için idealdir.

Bir de progressive delay stratejisi var ki ben bunu çok seviyorum. İlk 3 başarısız giriş denemesinde anında cevap verirsiniz, 4. denemede 1 saniye bekletirsiniz, 5. denemede 2 saniye, 6. denemede 4 saniye... Üssel artış ile saldırgan her denemede daha uzun beklemek zorunda kalır. Bu brute force'u pratik olarak imkansız hale getirir.

Ayrıca sadece IP bazlı limit koymak yetmez. Saldırgan proxy arkasından binlerce farklı IP ile gelebilir. Login endpoint'inde hem IP hem kullanıcı adı bazlı limit koyun. Böylece aynı hesaba farklı IP'lerden de sınırlı sayıda deneme yapılabilir.

Production'da rate limit ayarlarınızı çok sıkı tutmayın, gerçek kullanıcıları kızdırırsınız. Özellikle paylaşımlı IP'lerde (ofis, okul) çok kullanıcı aynı IP'den gelir. Bu durumlar için IP + User-Agent kombinasyonu veya authenticated kullanıcılar için daha yüksek limitler düşünün.

Kolay gelsin!
 

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

Geri
Üst