İnternetteki güvenlik tavsiyelerinin çoğu, kimsenin uygulamadığı bir uyumluluk listesi gibi okunur. Bu rehber farklı. Yeterince üretim kod tabanını denetledik; hangi hataların tekrar tekrar karşımıza çıktığını ve hangi “en iyi pratiklerin” aslında tiyatro olduğunu biliyoruz.
Eğer hâlâ parolaları bcrypt, scrypt veya argon2id dışında bir şeyle saklıyorsanız okumayı bırakın ve şimdi düzeltin. Sonra geri dönün.
OWASP Top 10: Gerçekte Canınızı Yakacak Sıralama
OWASP Top 10 2021 iyi bir liste, ama hepsini eşit önceliklendirmek hata. Gerçek dünyada ihlallerin yaşandığı sıra şu:
- Broken Access Control (A01) — açık ara en çok sömürülen. Giriş yapmış bir kullanıcı
/api/orders/123’ü/api/orders/124yapıp başkasının faturasını görüyor. Denetimlerin yaklaşık %60’ında karşımıza çıkıyor. - Injection (A03) — SQL injection çözüldü sanılıyor ama ORM doğru kullanılmadığı her yerde hâlâ var.
- Cryptographic Failures (A02) — genelde “API token’larını düz metin sakladık” veya “fonksiyon hazırdı diye MD5 kullandık” anlamına gelir.
- Identification & Authentication Failures (A07) — el yapımı JWT mantığı,
/loginüzerinde rate limit yok, MFA yok. - Software & Data Integrity Failures (A08) — tedarik zinciri kategorisi. npm tam burada ısırıyor.
- Security Misconfiguration (A05) — varsayılan S3 bucket’ları, prod’da debug modu, stack trace sızdıran hata mesajları.
- Vulnerable Components (A06) — bilinen CVE’leri olan eski bağımlılıklar.
- SSRF (A10) — sunucu kullanıcının verdiği URL’yi çekiyor ve kazara
169.254.169.254’a vuruyor. - Insecure Design (A04) — hiçbir yamanın çözmediği mimari sorunlar.
- Security Logging Failures (A09) — altı ay önce hacklendiniz, kimse fark etmedi.
A01 ve A03’ü bugün düzeltirseniz, çoğu web uygulamasının pratik saldırı yüzeyinin büyük kısmını yok etmişsiniz olur. Geri kalanı önemli, ama buradan başlayın.
Kimlik Doğrulama: Kendinizinkini Yazmayı Bırakın
Sizi en çok acıdan kurtaracak tek tavsiye şu: 2025’te kendi kimlik doğrulama sisteminizi yazmayın. Auth0, Clerk, Supabase Auth, WorkOS kullanın ya da NextAuth/Lucia gibi denenmiş framework primitive’lerine başvurun.
Authentication’ın %80’ini doğru yapmak aldatıcı şekilde kolaydır; son %20’sini doğru yapmak felaket derecede zor. Session fixation, parola karşılaştırmasında timing saldırıları, güvenli cookie flag’leri, hesap enumeration, kurtarma akışı üzerinden MFA bypass, OAuth callback doğrulaması — bunların her biri saygı duyduğumuz ekipleri ısırdı.
İlla kendi yazacaksanız, httpOnly, Secure, SameSite=Lax cookie’lerle proper session-based auth kullanın. localStorage’da JWT değil. Asla localStorage’da JWT olmaz.
// Açık: token herhangi bir XSS'ten erişilebilir
localStorage.setItem("token", jwt);
// Daha iyi: sunucunun set ettiği httpOnly cookie
res.cookie("session", sessionId, {
httpOnly: true,
secure: true,
sameSite: "lax",
maxAge: 1000 * 60 * 60 * 24 * 7,
});
Parola hash’leme? Mantıklı parametrelerle argon2id, veya bcrypt cost 12+. Başka her şey — SHA-256, düşük iterasyonlu PBKDF2, “kendimiz tuzladık” — yanlıştır.
Yetkilendirme: RBAC, ABAC mi ReBAC mi?
Authentication “sen kimsin?” diye sorar. Authorization “ne yapabilirsin?” diye sorar — ve uygulamaların çoğunda sessizce çuvalladığı yer ikincisidir.
- RBAC (Rol Tabanlı) — kullanıcıların rolleri, rollerin izinleri olur. Doğru olduğu yer: SaaS uygulamalarının çoğu, dahili araçlar, “admin / üye / izleyici” yeterli olan her şey.
- ABAC (Öznitelik Tabanlı) — kararlar özniteliklere göre verilir (departman, günün saati, doküman sınıflandırması). Doğru olduğu yer: sağlık, finans, karmaşık tenant kuralları olan multi-tenant sistemler.
- ReBAC (İlişki Tabanlı) — Google Zanzibar’dan esinlenir. “Kullanıcı X dokümanı Y’yi görebilir çünkü X, Y’yi içeren F klasörüne erişimi olan Z grubunun üyesidir.” Doğru olduğu yer: işbirlikçi uygulamalar, dosya paylaşımı, derin sahiplik ilişkileri. Araçlar: OpenFGA, SpiceDB, Oso.
Birini seçin ve her istekte sunucu tarafında uygulayın. UI’da bir butonu gizlemek yetkilendirme değildir.
# Açık: istemciye güvenilen rol
@app.route("/admin/users")
def admin_users():
return User.all() # kontrol yok
# Düzeltilmiş: sunucu uygular, default deny
@app.route("/admin/users")
@require_permission("users:read")
def admin_users():
return User.all()
Dağıtık sistemlerde servisten servise kimlik doğrulama için mikroservis mimarisi rehberimize bakın — mTLS ve kısa ömürlü servis token’ları doğru varsayılanlardır.
Girdi Doğrulama: Sunucu Tarafında, Her Zaman, Şema ile
İstemci tarafı doğrulama bir UX özelliğidir. Güvenlik kontrolü değildir. Saldırgan sizin React uygulamanızı çalıştırmıyor.
Bir şema doğrulayıcı kullanın — zod, valibot, joi, pydantic, stack’inizde ne varsa — ve okuduğunuz her request body’yi, query string’i ve header’ı doğrulayın.
// Açık
app.post("/users", (req, res) => {
db.user.create({ data: req.body }); // mass assignment, tip karışıklığı, hepsi
});
// Düzeltilmiş
const CreateUser = z.object({
email: z.string().email(),
name: z.string().min(1).max(120),
role: z.enum(["member", "viewer"]), // admin seçilemez
});
app.post("/users", (req, res) => {
const data = CreateUser.parse(req.body);
db.user.create({ data });
});
SQL injection 2024’te hâlâ OWASP Top 10’da çünkü geliştiriciler hâlâ string concatenate ediyor. Parametreli sorgular opsiyonel değildir. Her modern ORM ve DB driver bunları destekler. Kullanın. Güvenli sorgu kalıpları için veritabanı optimizasyon rehberimize göz atın.
// Açık
db.query(`SELECT * FROM users WHERE email = '${email}'`);
// Düzeltilmiş
db.query("SELECT * FROM users WHERE email = $1", [email]);
XSS ve Bugün Yayına Almanız Gereken CSP Başlığı
Modern bir framework kullanıyorsanız (React, Vue, Svelte hepsi varsayılan olarak escape eder) ve dangerouslySetInnerHTML / v-html’i kullanıcı girdisiyle çağırmıyorsanız XSS büyük ölçüde çözülmüş bir problemdir. Hâlâ ısırdığı yerler: sunucu tarafında render edilen template’ler, sanitize edilmeden render edilen Markdown ve eksik ya da unsafe-inline ayarlı CSP başlıkları.
Bu başlıkları her response’da gönderin. CSP’yi gerçek asset host’larınıza göre ayarlayın:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'nonce-{random}'; img-src 'self' data: https:; connect-src 'self' https://api.yourdomain.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=()
Cross-Origin-Opener-Policy: same-origin
Evet, nonce tabanlı CSP unsafe-inline’dan daha fazla iş gerektirir. Yine de yapın. web.dev CSP rehberi istek başına nonce üretimini anlatıyor.
CSRF için modern SameSite=Lax cookie’ler çoğu durumu ücretsiz çözer — ama cross-origin POST kabul ediyorsanız double-submit token veya Origin header kontrolü kullanın.
Secret’lar, Tedarik Zinciri ve DDoS
Secret yönetimi. Git’e commit edilmiş .env dosyalarında secret yok. İstemci bundle’larında API key yok. AWS Secrets Manager, HashiCorp Vault, Doppler veya platformunuzun eşdeğerini kullanın. Üç ayda bir rotate edin. Erişimi denetleyin. Operasyonel kalıpları DevOps en iyi uygulamalar rehberimizde ele alıyoruz.
Tedarik zinciri. Tek bir ele geçirilmiş npm paketi build sunucunuzu sahiplenebilir. İşe yarayan varsayılanlar:
- CI’da
npm auditçalıştırın ve high/critical’da fail edin - Güvenlik yamaları için otomatik PR ile Dependabot veya Renovate aktif edin
- Lockfile ile versiyonları sabitleyin ve lockfile diff’lerini inceleyin
- Uyumluluk ve denetim için SBOM üretin (Syft, CycloneDX)
- Postinstall malware’i engellemek için mümkün olduğunda CI’da
npm ci --ignore-scriptskullanın
DDoS. 2 Tbps’lik bir saldırıyı nginx ile bertaraf edemezsiniz. Uygulamanızın önüne Cloudflare, AWS Shield veya Fastly koyun. IP başına ve kimlik doğrulanmış kullanıcı başına rate limit ayarlayın. Bulut göç rehberimiz edge güvenliğini daha detaylı kapsıyor.
Uyumluluk: KVKK, GDPR ve PCI-DSS — Tiyatrosuz
Türk kullanıcılarınız varsa KVKK (Kişisel Verilerin Korunması Kanunu) uygulanır — ve GDPR uyumluluğunun otomatik olarak karşılamadığı kendine özgü veri ikametgâhı (data residency) ve açık rıza gereklilikleri vardır. KVKK’ya göre VERBİS kaydı, açık rıza metinleri ve yurt dışına veri aktarımında ek koşullar gerekir. Avrupalı kullanıcılarınız varsa GDPR uygulanır. Kart verisine dokunuyorsanız “sadece geçiriyoruz” deseniz bile PCI-DSS uygulanır.
Pratik temel:
- Hangi kişisel veriyi neden topladığınızı dokümante edin
- Veri silme ve dışa aktarma uç noktalarını teorik değil gerçek tutun
- Hassas veriye erişimi loglayın — KVKK ve GDPR ikisi de kimin neye eriştiğini bilmenizi bekler
- PCI-DSS için en ucuz yol ham kart numarasına asla dokunmamaktır. Iyzico, Stripe Elements veya başka bir tokenize eden işlemci kullanın ki kart verisi sunucunuza hiç ulaşmasın
- PII’yi at rest şifreleyin, sadece “veritabanı sunucusunda full-disk encryption var” değil — kolon bazında şifreleyin
Uyumluluk iyi mühendisliğin yan etkisidir. Erişim loglarınız, silme akışlarınız ve şifrelemeniz gerçekse, denetçinin işi sadece evrak işine döner.
Güvenlik Denetimi mi Lazım?
Güvenliğin en zor kısmı, neyi bilmediğinizi bilmemektir. Çoğu ekip authorization’ının bozuk olduğunu ancak bir müşteri başkasının verisini gördüğünü bildirdiğinde fark ediyor. Bu, öğrenmek için pahalı bir yol.
Web uygulamalarında hedefli güvenlik denetimleri yapıyoruz — OWASP hizalı, 60 sayfalık kimsenin okumadığı PDF yerine somut remediation PR’larıyla. Bir şeyler ters gitmeden önce kimlik doğrulamanıza, yetkilendirmenize veya genel saldırı yüzeyinize ikinci bir göz atılmasını istiyorsanız bizimle iletişime geçin. Tek bir konuşma genelde gerçek bir sorununuz mu yoksa sağlıklı bir paranoyanız mı olduğunu netleştirir.