Aikido

Node.js sunucularında küresel değişkenler neden veri sızıntılarına yol açar?

Güvenlik

Kural
Kaçın istenmeyen küresel değişken önbelleklemeden kaçının. Node.js'de Node.js
ve Python sunucularda, global değişkenler kalıcı istekler
istekler arasında bu da veri sızıntılarına ve yarış koşullarına yol açar.

Desteklenen diller: JavaScript, TypeScript, Python

Giriş

Node.js sunucularındaki küresel değişkenler, yalnızca tek bir istek süresince değil, işlemin ömrü boyunca kalıcıdır. İstek işleyicileri kullanıcı verilerini küresel değişkenlerde sakladığında, bu verilere farklı kullanıcılardan gelen sonraki istekler de erişebilir. Bu durum, kullanıcı A’nın oturum verilerinin, kimlik doğrulama belirteçlerinin veya kişisel bilgilerinin kullanıcı B’ye sızmasına yol açan güvenlik açıkları yaratır.

Neden önemli?

Güvenlik riskleri (veri sızıntıları): Kullanıcıya özgü verileri önbelleğe alan küresel değişkenler, istekler arası veri sızıntılarına yol açar. Bir kullanıcının kimlik doğrulama durumu, oturum verileri veya kişisel bilgileri diğer kullanıcılar tarafından görülebilir hale gelir; bu da gizlilik ve güvenlik sınırlarını ihlal eder.

Yarış durumları: Birden fazla eşzamanlı istek aynı küresel değişkeni değiştirdiğinde, öngörülemeyen davranışların ortaya çıkma olasılığı yüksektir. İşlem sırasında Kullanıcı A’nın verileri, Kullanıcı B’nin isteği tarafından üzerine yazılabilir; bu da hatalı hesaplamalara, bozuk duruma veya kullanıcıların birbirlerinin verilerini görmesine yol açabilir.

Hata ayıklama karmaşıklığı: Küresel değişken önbelleklemesinden kaynaklanan sorunların yeniden canlandırılması, istek zamanlamasına ve eşzamanlılığa bağlı olması nedeniyle bilindiği üzere oldukça zordur. Bu hatalar, yük altındaki üretim ortamında aralıklı olarak ortaya çıkar, ancak tek iş parçacıklı geliştirme testlerinde nadiren görülür.

Bellek sızıntıları: Temizlenmeden veri biriktiren küresel değişkenler, zamanla sınırsız bir şekilde büyür. Her istek, küresel önbelleklere veya dizilere daha fazla veri ekler; bu da sonunda sunucu belleğini tüketir ve işlemlerin yeniden başlatılmasını gerektirir.

Kod örnekleri

❌ Uygun değil:

let currentUser = null;
let requestData = {};

app.get('/profile', async (req, res) => {
    currentUser = await getUserById(req.userId);
    requestData = req.body;

    const profile = await buildUserProfile(currentUser);
    res.json(profile);
});

function buildUserProfile(user) {
    return {
        name: currentUser.name,
        data: requestData
    };
}

Neden yanlış: currentUser ve requestData küresel değişkenleri, istekler arasında kalıcıdır. Birden fazla istek eşzamanlı olarak yürütüldüğünde, kullanıcı A’nın buildUserProfile() işlevi hâlâ yürütülürken kullanıcı B’nin isteği currentUser değişkenini üzerine yazabilir ve bu da kullanıcı A’nın kullanıcı B’nin verilerini görmesine neden olabilir.

✅ Uygunluk:

app.get('/profile', async (req, res) => {
    const currentUser = await getUserById(req.userId);
    const requestData = req.body;

    const profile = buildUserProfile(currentUser, requestData);
    res.json(profile);
});

function buildUserProfile(user, data) {
    return {
        name: user.name,
        data: data
    };
}

Bunun önemi: İsteğe özgü tüm veriler, istek işleyicisinin kapsamına giren yerel değişkenlerde saklanır. Her isteğin, diğer eşzamanlı isteklere sızamayacak şekilde izole edilmiş bir durumu vardır. İşlevler, küresel duruma erişmek yerine parametreler aracılığıyla veri alır; bu da yarış koşullarını ortadan kaldırır.

Sonuç

Tüm istekle ilgili verileri yerel değişkenlerde veya çerçevenizin sağladığı istek nesnelerinde saklayın. Küresel değişkenleri yalnızca yapılandırma, bağlantı havuzları veya salt okunur önbellekler gibi gerçekten paylaşılan durumlar için kullanın. Küresel durumun gerekli olduğu durumlarda, uygun eşzamanlılık denetimleri kullanın ve verilerin hiçbir zaman kullanıcıya özgü olmamasına dikkat edin.

Sık Sorulan Sorular

Sorularınız mı var?

Node.js'de küresel değişkenleri ne zaman güvenle kullanabiliriz?

Küresel değişkenler, tüm istekler için geçerli olan salt okunur veriler için güvenlidir: uygulama yapılandırması, veritabanı bağlantı havuzları, derlenmiş şablonlar veya paylaşılan yardımcı programlar. İsteğe veya kullanıcıya özgü verileri asla küresel olarak saklamayın. Verileri küresel olarak önbelleğe almanız gerekiyorsa, verilerin doğru şekilde anahtarlanmış olduğundan ve erişimin iş parçacığı açısından güvenli olduğundan emin olun ya da Redis gibi uygun önbellekleme çözümlerini kullanın.

Peki ya açıkça küresel olarak tanımlanmamış modül düzeyindeki değişkenler ne olacak?

Modül düzeyindeki değişkenler (dosya kapsamındaki const, let, var), Node.js’de tam olarak küresel değişkenler gibi davranır. Bu değişkenler tüm istekler boyunca kalıcıdır ve tüm eşzamanlı istek işleyicileri tarafından paylaşılır. Aynı veri sızıntısı ve yarış durumu riskleri geçerlidir. Modül düzeyindeki değişkenlere, açıkça tanımlanmış küresel değişkenlere gösterdiğiniz özenle yaklaşın.

Orta katman yazılımı ile rota işleyicileri arasında verileri nasıl paylaşabilirim?

Çerçevenizin sağladığı istek nesnesi özelliklerini kullanın. Express, req.locals’ı veya req üzerinde özel özellikler sunar. Fastify’da ise request.decorateRequest() işlevi bulunur. Bu nesneler istek kapsamındadır ve istek tamamlandıktan sonra otomatik olarak temizlenir; böylece istekler arasında sızıntılar önlenir.

Peki ya singleton kalıpları ve sınıf örnekleri?

Modül düzeyindeki singleton örnekleri küresel durumdur. Eğer istek özelinde veriler içeriyorlarsa, aynı sorunlar geçerlidir. Singleton’ları durum içermeyen şekilde tasarlayın ya da yalnızca yapılandırma bilgilerini barındıracak şekilde düzenleyin. Durum içeren işlemler için, her istek başına yeni örnekler oluşturun ya da izolasyonu sağlayan fabrika kalıplarını kullanın.

Geliştirme aşamasında bu sorunları nasıl tespit edebilirim?

Farklı kullanıcı bağlamlarını kullanarak eşzamanlı isteklerle yük testleri gerçekleştirin. Yarış durumları ve veri sızıntıları, sıralı testlerde genellikle ortaya çıkmaz. Eşzamanlı yük oluşturmak için Apache Bench veya autocannon gibi araçları kullanın. Bir isteğin verilerinin başka bir istekte ne zaman ortaya çıktığını izlemek için istek kimliklerini içeren günlük kaydı ekleyin.

Bu, AWS Lambda gibi sunucusuz işlevler için de geçerli mi?

Kısmen. Her Lambda çağrısı yeni bir yürütme ortamına sahip olur, ancak konteyner farklı çağrılar arasında yeniden kullanılabilir. Aynı konteyneri yeniden kullanan çağrılar arasında küresel değişkenler korunur. Küresel değişkenlerin sıfırlanacağına güvenmeyin. Her zamanki uygulamaları izleyin: istek verilerini yerel kapsamda tutun.

Peki ya Python WSGI/ASGI uygulamaları?

Aynı ilkeler geçerlidir. Python web sunucuları çok iş parçacıklı veya asenkron olarak çalışır; bu nedenle modül düzeyindeki değişkenler tüm istekler arasında paylaşılır. Flask’ın `g` nesnesi ve FastAPI’nin bağımlılık enjeksiyonu, istek kapsamlı depolama imkânı sunar. Django’da ise istek nesneleri bulunur. İstek verileri için modül genel değişkenleri yerine çerçeve tarafından sağlanan mekanizmaları kullanın.

Şimdi güvenliğinizi sağlayın

Kodunuzu, bulutunuzu ve çalışma zamanınızı tek bir merkezi sistemde güvenceye alın.
Güvenlik açıklarını otomatik olarak hızla bulun ve düzeltin.

Kredi kartı gerekmez | Tarama sonuçları 32 saniyede.