Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 10

Katmanlar Arası Veri Akışı ve Güven Sınırı İhlalleri Tespiti

Recommended resources

Harika bir ilerleme kaydettik. Önceki dersimizde, bir veri akışındaki temizleme (sanitization) ve doğrulama (validation) kontrollerinin etkinliğini, verinin kullanılacağı nihai hedefin (sink) bağlamına göre nasıl değerlendireceğimizi derinlemesine inceledik. "İşlem sırası" ve "bağlamsal doğruluk" gibi prensiplerin, bir güvenlik kontrolünü başarılı veya başarısız kılan kritik faktörler olduğunu gördük. Artık analizlerimizde sadece bir kontrolün varlığına değil, onun doğruluğuna ve uygulanma şekline odaklanabiliyoruz.

Bu dersimizde ise merceğimizi biraz daha genişleterek, modern uygulamaların katmanlı yapısına odaklanacağız. Verinin tek bir uygulama içindeki yolculuğunu değil, frontend'den API'ye, oradan farklı backend servislerine ve nihayetinde veritabanına uzanan katmanlar arası seyahatini izleyeceğiz. Bu dersin temel amacı, bu katmanlar arasındaki güven sınırlarını (trust boundaries) ve bu sınırlardaki zayıf varsayımlar nedeniyle ortaya çıkan kritik zafiyetleri, yani güven sınırı ihlallerini tespit etme yeteneğinizi geliştirmektir.

Modern Mimarilerde Güven Sınırlarını Yeniden Düşünmek

Geleneksel olarak güven sınırı, "dış dünya" (kullanıcı) ile "iç sistem" (sunucu) arasındaki net bir çizgi olarak düşünülürdü. Ancak günümüzün dağıtık mimarilerinde (mikroservisler, serverless, SPA - Single Page Applications) bu çizgi hem çoğalmış hem de bulanıklaşmıştır. Artık her bir bileşen, potansiyel bir güven sınırı oluşturur:

  • Kullanıcının tarayıcısı ile CDN/frontend sunucusu arası.
  • Frontend sunucusu ile API Gateway arası.
  • API Gateway ile ana backend servisi arası.
  • Bir backend servisi ile diğer bir backend servisi arası (örneğin, sipariş servisi ile envanter servisi).
  • Uygulama ile veritabanı, cache veya mesaj kuyruğu gibi harici sistemler arası.

Bu sınırların her biri, bir önceki katmandan gelen veriye dair bir varsayım içerir. Zafiyetler, tam da bu varsayımların istismar edildiği anlarda doğar. "Sıfır Güven" (Zero Trust) mimari modeli, bu yaklaşımı en iyi özetleyen kavramsal çerçevedir. Bu modele göre, ağın "içinde" olmanın hiçbir anlamı yoktur; her istek, geldiği yer ne olursa olsun doğrulanmalıdır.

Bu diyagram bir Sıfır Güven (Zero Trust) mimarisinin temel bileşenlerini göstermektedir. "Subject" (örn: kullanıcı veya servis), bir "Enterprise Resource" (örn: API veya veritabanı) üzerine erişmeye çalıştığında, isteği bir "Policy Enforcement Point" (PEP) tarafından durdurulur. PEP, kararı kendisi vermez; "Policy Decision Point" (PDP - Policy Engine & Administrator) olarak adlandırılan merkezi bir mantık birimine danışır. PDP, isteğin meşru olup olmadığına karar verirken kimlik yönetimi, tehdit istihbaratı, veri erişim politikaları gibi birçok faktörü değerlendirir. Kod analizi perspektifinden bizim görevimiz, bu PEP'lerin nerede olması gerektiğini ve doğru çalışıp çalışmadığını tespit etmektir.

Bu modeldeki "Policy Enforcement Point" (PEP), tam olarak bizim kodda aradığımız şeydir: bir güven sınırında durup gelen isteği sorgulayan, doğrulayan ve yetkilendiren kod bloğu. Bir ihlal, ya bu noktanın hiç olmamasından ya da politikasının (policy) hatalı olmasından kaynaklanır.


En Temel İhlal: Üst Katmana Körü Körüne Güvenmek

Güven sınırı ihlallerinin en yaygın ve temel nedeni, bir katmanın kendisinden önceki katmana (upstream) sorgusuz sualsiz güvenmesidir.

  • Backend'in Frontend'e Güveni: Geliştiriciler, "Bu istek benim yazdığım JavaScript kodundan geliyor, o halde güvenlidir" diye düşünebilir. Frontend'de yapılan istemci taraflı doğrulamalar (örneğin, bir form alanının boş bırakılamaması veya bir ürün fiyatının JavaScript ile hesaplanması), bir proxy aracıyla (Burp Suite gibi) isteği değiştirebilen bir saldırgan için hiçbir anlam ifade etmez. Kural 1: İstemciden (client) gelen hiçbir veriye, sunucu tarafında yeniden doğrulanmadan asla güvenilmez. Bu kural, API endpoint'lerini, form gönderilerini ve hatta frontend'in backend'e gönderdiği "güvenli" olduğu varsayılan yapılandırma bilgilerini de kapsar.

  • Servislerin Birbirine Güveni: Mikroservis mimarilerinde, "Sipariş servisi ile Kullanıcı servisi aynı ağda ve ikisini de biz yazdık, o halde birbirlerine güvenebilirler" varsayımı ölümcül olabilir. Örneğin, Sipariş servisi, Kullanıcı servisinden bir profil bilgisi isterken GET /api/users/123 gibi bir istek yapabilir. Eğer Kullanıcı servisi, bu isteği yapanın Sipariş servisi olduğunu görüp isteğin geldiği asıl kullanıcının (Sipariş servisine isteği başlatan son kullanıcı) 123 ID'li profili görme yetkisi olup olmadığını kontrol etmezse, ciddi bir yetki zafiyeti (Broken Object Level Authorization - BOLA) oluşur. Kural 2: Bir servisten gelen istek, son kullanıcıdan gelmiş gibi muamele görmelidir. Yetkilendirme bağlamı (genellikle bir JWT içinde taşınır) servisler arasında kaybolmamalı ve her servis tarafından yeniden doğrulanmalıdır.

Aşağıdaki diyagram, harici bir kimlik doğrulama sağlayıcısı ile olan etkileşimi gösterir. Bu, servisler arası güven ilişkisine güzel bir analog oluşturur.

Bu akışta, uygulama kimlik doğrulamayı harici bir OAuth2 sağlayıcısına delege eder. Sağlayıcıdan bir "ID Token" veya "Access Token" geldiğinde, uygulama bu token'a güvenir (Trust Boundary'yi geçen veri). Ancak bu güvenin ardından, uygulama kendi oturumunu (session) oluşturmalı ve yetkilendirme kararlarını bu oturuma göre vermelidir. Harici sağlayıcıdan gelen veriye körü körüne güvenip, içeriğini (örn: `scope`, `claims`) doğrulamadan işlem yapmak bir güven sınırı ihlalidir.

Vaka Analizi: Framework Davranışlarındaki Örtük İhlaller

Bazen güven sınırı ihlalleri, geliştiricinin yazdığı bariz bir mantık hatasından değil, kullandığı framework'ün beklenmedik veya az bilinen bir davranışından kaynaklanır. Bu tür zafiyetleri bulmak, "uzman gözü" geliştirmenin en önemli parçasıdır.

Şimdi, Mehmet İnce'nin hazırladığı kısa ama son derece öğretici bir video üzerinden, Express.js (Node.js için popüler bir web framework'ü) özelindeki bir zafiyeti inceleyelim. Bu vaka, bir güvenlik kontrolünün (middleware) framework'ün routing katmanı tarafından nasıl atlatılabileceğini mükemmel bir şekilde göstermektedir.

Bu Javascript kodunda ki güvenlik açığını bulabilir misin ?

Bu video, basit bir Express.js uygulamasındaki bir güvenlik açığı bulmacası sunuyor. Kod, /secret yoluna erişimi engelleyen bir middleware içeriyor. Videoyu izlerken, bu bariz engelin nasıl aşılabileceğini ve bu durumun katmanlar arası veri akışıyla nasıl bir ilişkisi olduğunu düşünün.

Önce problemin tanımını izleyin. Kodda /secret yoluna gelen istekleri açıkça engelleyen bir middleware katmanı var. Normal bir istek gerçekten de engelleniyor. Şimdi, zafiyetin sömürülmesini gösteren bölümü dikkatle izleyin. Saldırgan, path olarak hedeflenen URL'in kendisini tekrar göndererek (http://localhost:3000/http://localhost:3000/secret) bu engeli aşıyor. Son olarak, "Neden?" sorusunun sorulduğu bölümü dinleyin. Video, cevabı doğrudan vermeyerek bizi framework'ün iç işleyişini araştırmaya teşvik ediyor.

Peki burada tam olarak ne oldu? Bu bir güven sınırı ihlalidir, çünkü iki farklı katman, "path" (yol) verisini farklı yorumlamıştır:

  1. Middleware Katmanı (Kontrol Katmanı): app.use('/secret', ...) ile tanımlanan bu katman, gelen isteğin req.path değerinin /secret ile başlayıp başlamadığına bakar. İlk istek http://localhost:3000/http://localhost:3000/secret olduğunda, Express.js tarafından parse edilen path, URL'in path kısmıdır, yani /http://localhost:3000/secret. Bu, /secret ile başlamadığı için middleware bu isteği engellemez ve "geç" der.

  2. Routing Katmanı (İşlem Katmanı): Middleware'i geçen istek, Express'in ana router'ına ulaşır. Router, bir path'in içinde tam bir URL gördüğünde, bu URL'i ayrıştırır ve isteği o URL'in path kısmına yönlendirir. Yani, http://localhost:3000/secret path'ini görür, host kısmını atar ve isteği effectively /secret yoluna yönlendirir.

Buradaki ihlal, middleware katmanının, routing katmanının daha sonra yapacağı "path normalizasyonu" ve "URL parsing" işlemini öngörememesidir. Middleware, "güvenli" sandığı bir path'e izin verirken, alt katman olan router bu "güvenli" path'i "tehlikeli" bir hedefe dönüştürmüştür. Bu, önceki derste gördüğümüz "Önce kurallı hale getir, sonra kontrol et" prensibinin framework seviyesindeki bir ihlalidir.


Katmanlar Arası Akışı Analiz Etme Stratejisi

Bu örneklerden yola çıkarak, bir kod analisti olarak katmanlar arası veri akışını incelerken izlemeniz gereken adımları şöyle özetleyebiliriz:

  1. Mimarinin Haritasını Çıkarın: Sistemin tüm bileşenlerini (frontend, load balancer, API gateway, servisler, veritabanları vb.) ve aralarındaki iletişim kanallarını (HTTP, gRPC, mesaj kuyruğu) belirleyin.
  2. Güven Sınırlarını İşaretleyin: Verinin bir bileşenden diğerine geçtiği her noktayı bir güven sınırı olarak kabul edin.
  3. Kritik Veriyi Takip Edin: Bir kullanıcı ID'si, bir oturum token'ı, bir dosya adı veya bir para miktarı gibi hassas veya kontrol mekanizmalarında kullanılan bir veriyi seçin ve bu verinin sınırlardan geçerken nasıl değiştiğini veya değişmediğini izleyin.
  4. Her Sınırda Varsayımları Sorgulayın:
    • Veri Doğrulaması: Alıcı katman, veriyi yeniden doğruluyor mu, yoksa gönderen katmana güveniyor mu? Örneğin, frontend'den gelen bir role: "admin" JSON alanını backend doğrudan işliyor mu?
    • Yetkilendirme Kontrolü: Alıcı katman, isteğin orijinal kullanıcısının bu veriye veya eyleme yetkisi olup olmadığını kontrol ediyor mu, yoksa sadece isteği yapan servise mi güveniyor?
    • Başlık (Header) Güveni: Bir katman, X-Forwarded-For veya X-User-ID gibi bir HTTP başlığına güveniyor mu? Bu başlığı sadece güvenilir bir yukarı akım bileşeni (örneğin API Gateway) tarafından ayarlandığı ve dışarıdan manipüle edilemediği garanti altında mı?
  5. Bağlam Değişikliklerini Ara: Bir katmanda zararsız olan bir veri, diğer katmanda tehlikeli bir bağlamda mı kullanılıyor? (Örn: Frontend'den gelen bir "tema adı", backend'de bir dosya yolunun parçası olarak mı kullanılıyor?)

Sonuç

Bu derste, modern uygulamaların karmaşık yapılarında güvenin nasıl yönetilmesi gerektiğini ve bu güvenin kötüye kullanıldığı durumları nasıl tespit edeceğimizi öğrendik. Gördük ki, katmanlar sadece birer soyutlama aracı değil, aynı zamanda potansiyel güvenlik zafiyetlerinin gizlendiği sınırlardır.

Temel Çıkarımlar:

  • Paranoyak Olun: Bir kod analisti olarak varsayılan duruşunuz "Sıfır Güven" olmalıdır. Her katman sınırında, bir önceki katmanın kötü niyetli olabileceğini varsayın.
  • Asla İstemciye Güvenmeyin: İstemci tarafı kontrolleri sadece kullanıcı deneyimi (UX) içindir, güvenlik için değil. Tüm güvenlik mantığı sunucuda uygulanmalıdır.
  • Servisler Arası Güven Tehlikelidir: Mikroservisler, yetkilendirme bağlamını her istekte taşımalı ve her servis bu bağlamı kendi içinde yeniden doğrulamalıdır.
  • Framework'ünüzü Derinlemesine Anlayın: Framework'lerin istek işleme, routing ve veri ayrıştırma (parsing) mekanizmalarındaki nüanslar, en beklenmedik güven sınırı ihlallerine yol açabilir.

Artık bir verinin sadece bir fonksiyon içindeki değil, tüm bir mimari içindeki yolculuğunu analiz edebilecek ve katmanların birbirine olan örtük güveninin yarattığı riskleri ortaya çıkarabilecek donanıma sahipsiniz.

Bir sonraki dersimizde, güven sınırlarında uygulanan en temel kontrol mekanizmalarından birine odaklanacağız: kimlik doğrulama. Alternatif kod yolları, geri dönüş mekanizmaları ve hata yönetimi mantığı üzerinden kimlik doğrulamanın nasıl atlatılabileceğini inceleyerek, bu kritik güvenlik kapısındaki zafiyetleri tespit etmeyi öğreneceğiz.