Sunucu olmayan mimariler, uygulamaları oluşturma ve dağıtma biçimimizi kökten değiştirdi; ölçeklenebilirlik ve azaltılmış operasyonel yük sunar. Ancak "sunucu olmayan" unvanı bazen sahte bir güvenlik hissi yaratabilir. Altyapıyı yönetmiyor olmanız, uygulama mantığınızı güvence altına almakla sorumlu olmadığınız anlamına gelmez. Aslında, sunucu olmayan fonksiyonların geçici yapısı, güvenlik stratejisinde bir değişim gerektiren benzersiz saldırı vektörleri getirir.
Sunucu olmayan güvenliğin ön saflarında iki temel sütun yer alır: titiz girdi doğrulama ve sıkı Kimlik ve Erişim Yönetimi (IAM) politikaları. Bu yazı, bunların neden kritik olduğunu ve dağıtımınızı güçlendirmek için uygulanabilir kod örnekleri sunar.
Güvenin Yanılsaması: Neden Girdi Doğrulama Müzakere Konusu Değildir?
Sunucu olmayan modele geçtiğinizde, fonksiyonlarınız genellikle API ağ geçitleri aracılığıyla doğrudan açığa çıkar veya S3 kovaları veya DynamoDB akışları gibi olay kaynakları tarafından tetiklenir. Saldırganlar, bu uç noktalara hatalı, aşırı büyük veya kötü amaçlı yükler göndermeyi deneyecektir. Doğrulama olmadan, kodunuz NoSQL enjeksiyonuna, arabellek taşmalarına ve Hizmet Reddi (DoS) ile sonuçlanabilecek beklenmeyen çalışma zamanı hatalarına karşı savunmasız hale gelir.
Her zaman tüm girdilerin düşmanca olduğunu varsayın. Veriler bir HTTP üst bilgisinden, bir JSON gövdesinden veya bir sorgu dizgisinden gelse de, iş mantığınıza temas etmeden önce temizlenmeli ve doğrulanmalıdır. Bu kural, yalnızca kullanıcı tarafından sağlanan veriler için değil, sistem tarafından oluşturulan olaylar için de geçerlidir.
Node.js'de Doğrulama Uygulama
Node.js tabanlı Lambda fonksiyonları için Zod veya Joi gibi kütüphaneler güçlü şema doğrulaması sağlar. Aşağıda, gelen JSON yüklerini doğrulamak için Zod kullanılarak hazırlanmış bir örnek bulunmaktadır. Bu, işleme başlamadan önce veri yapısının beklentilere uygun olduğundan ve türlerin doğru olduğundan emin olur.
const { z } = require('zod');
// Bir kullanıcı profili için şemayı tanımlayın
const UserSchema = z.object({
email: z.string().email("Geçersiz e-posta formatı"),
age: z.number().int().min(0).max(150, "Yaş gerçekçi olmalıdır"),
username: z.string().min(3).max(30).regex(/^[a-zA-Z0-9_]+$/, "Kullanıcı adı alfanümerik olmalıdır")
});
exports.handler = async (event) => {
try {
// Gelen olay gövdesini ayrıştırın ve doğrulayın
const validatedData = UserSchema.parse(event.body);
// Doğrulanmış verileri kullanarak iş mantığını yürütün
console.log("Doğrulanmış kullanıcı:", validatedData);
return {
statusCode: 200,
body: JSON.stringify({ message: "Başarılı" })
};
} catch (error) {
// Doğrulama hatalarını zarifçe yönetin
return {
statusCode: 400,
body: JSON.stringify({ error: error.errors })
};
}
};
Geçersiz verileri giriş noktasında reddederek, aşağı akışta oluşabilecek bozulmaları önler ve saldırı yüzeyini azaltırsınız. Bu yaklaşım aynı zamanda kendini açıklayan bir kod biçimi olarak da hizmet eder; fonksiyonunuzun ne beklediğini net bir şekilde tanımlar.
En Aza İndirilmiş Ayrıcalık: Sunucu Olmayan için IAM'i Ustalıkla Kullanma
Girdi doğrulama kodunuzu kötü verilerden korurken, IAM politikaları verilerinizi kötü amaçlı veya ele geçirilmiş kodlardan korur. Geleneksel sunucu ortamlarında geliştiriciler genellikle kolaylık için geniş izinler verir. Sunucu olmayan ortamlarda bu, felaket bir hatadır.
En az ayrıcalık ilkesi, her fonksiyonun belirli görevini yerine getirmek için gereken minimum izinlere sahip olması gerektiğini belirtir. Bir Lambda fonksiyonunun yalnızca belirli bir DynamoDB tablosundan okuması gerekiyorsa, öğeleri silme, diğer tablolardan okuma veya S3 kovalarına erişme iznine sahip olmamalıdır.
Tanımalı Ayrıcalıkların Belirlenmesi
Bir kullanıcının profilini DynamoDB'de güncelleyen bir fonksiyon düşünün. Bir acemi, fonksiyona AdministratorAccess veya geniş DynamoDB izinleri verebilir. Bunun yerine, belirli bir IAM politikası oluşturmalıyız.
Aşağıda, Lambda fonksiyonunu yalnızca belirli bir kaynak ARN'sinde UpdateItem işlemlerini gerçekleştirmeye kısıtlayan örnek bir IAM politika belgesi bulunmaktadır:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:UpdateItem"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/UserProfiles/index/*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
Burada iki noktaya dikkat edin. Birincisi, eylem yalnızca UpdateItem ile sınırlıdır; fonksiyon okuyamaz veya silemez. İkincisi, günlük kaydı izinleri ayrı olarak verilir; bu, fonksiyon ele geçirilirse saldırganın günlük kaydı devre dışı bırakarak izlerini kolayca gizleyemeyeceğini sağlar, ancak yine de diğer kritik kaynaklara erişimleri olmayacaktır.
Sonuç
Sunucu olmayan fonksiyonları güvence altına almak proaktif bir zihniyet gerektirir. Yalnızca çevre savunmalarına güvenemezsiniz; kodu sıkı girdi doğrulaması ile güvence altına almalı ve her türlü potansiyel ihlalin etkisini tanımı ayrıcalıklı IAM politikaları aracılığıyla sınırlamalısınız. Bu uygulamaları uygulayarak, sunucu olmayan uygulamalarınızın modern tehditlere karşı dirençli, güvenilir ve güvenli kalmasını sağlarsınız. Unutmayın, sunucu olmayan ortamlarda güvenlik bir eklenti değil; mimarinizin temel bir bileşenidir.