İçeriğe Atla
Mustafa Erbay
Rehberler · 12 dk okuma · görüntülenme Read in English

Bağımlılık Güvenliği: Build'i Durdurmak mı, Yoksa Uyarmak mı?

Yazılım projelerinde bağımlılık güvenliği yönetimi kritik bir konu. Build'i durdurarak sıfır tolerans mı, yoksa uyarı vererek esneklik mi? Sahadan edindiğim…

100%

Yazılım projelerinde bağımlılık yönetimi, ilk bakışta kolay gibi görünse de, işin içine güvenlik girdiğinde karmaşık bir hal alıyor. Birkaç kütüphane kullanmaya başladığınızda, bu kütüphanelerin kendi bağımlılıkları derken, kısa sürede yüzlerce, hatta binlerce paketi yönetir hale geliyorsunuz. İşte bu noktada Bağımlılık Güvenliği meselesi, “build’i durduralım mı, yoksa sadece uyarı mı verelim?” gibi temel bir soruyu beraberinde getiriyor.

Yıllardır hem büyük kurumsal projelerde hem de kendi yan ürünlerimde bu ikilemle çok karşılaştım. Her iki yaklaşımın da kendine göre avantajları ve dezavantajları var. Pragmatik bir sistemci olarak benim için önemli olan, geliştirme hızını tamamen öldürmeden, riski kabul edilebilir seviyede tutmaktır. Bu yazıda, bu kararı verirken göz önünde bulundurduğum noktaları ve sahada edindiğim tecrübeleri paylaşacağım.

Bağımlılık Güvenliği Neden Sürekli Baş Ağrısı Yaratıyor?

Projelerimizdeki bağımlılıklar, kullandığımız kütüphaneler ve onların kendi bağımlılıklarıdır. Modern yazılım geliştirme, bu paketler olmadan düşünülemez; çünkü her şeyi sıfırdan yazmak hem zaman kaybı hem de verimsizliktir. Ancak bu kolaylık, beraberinde ciddi güvenlik riskleri getiriyor.

Birkaç yıl önce bir e-ticaret sitesinin backend’inde çalışırken, sürekli güncellediğimiz bir paket yığını vardı. npm audit komutunu çalıştırdığımızda, çıkan sonuçlar bazen onlarca “High” seviye CVE gösteriyordu. Bunların çoğu doğrudan bizim kodumuzla ilgili olmasa bile, transitive dependency’ler üzerinden sisteme sızmış oluyordu. Bu durum, özellikle dışarıya açık bir sistemde büyük bir potansiyel zafiyet demekti. Açık kaynak kodlu kütüphanelerdeki her yeni zafiyet, projemizi doğrudan etkileyebilir.

Bu sürekli baş ağrısının ana nedenlerinden biri, bağımlılık ağacının karmaşıklığıdır. Bir kütüphanenin 5-10 bağımlılığı varsa, bunların da kendi bağımlılıkları olduğunda, zincir hızla uzar. Her bir bağımlılığın güvenliğini manuel olarak kontrol etmek neredeyse imkansızdır. Bu yüzden otomatize araçlara ihtiyaç duyuyoruz, ancak bu araçların da nasıl aksiyon alacağı kritik bir soru haline geliyor.

Build’i Durdurmak: Güvenlikte Sıfır Tolerans Yaklaşımı

Build’i durdurmak, yani “fail-fast” prensibini uygulamak, güvenlik konusunda sıfır tolerans gösteren bir yaklaşımdır. Bu yöntemde, CI/CD pipeline’ınız bir zafiyet tespit ettiğinde, kodun deploy edilmesini tamamen engeller. Temel argüman şudur: zafiyetli kodun production ortamına ulaşmasını baştan engellemek, sonradan oluşacak maliyetlerden çok daha düşüktür.

Bir bankanın iç platformu için geliştirdiğimiz bir serviste bu yaklaşımı benimsedik. Güvenlik ekibi, herhangi bir “High” veya “Critical” seviye CVE tespit edildiğinde build’in kesinlikle başarısız olmasını talep etti. Başlangıçta kulağa mantıklı geliyordu: temiz kod, güvenli sistem. Ancak bu durum, geliştirici ekibinde ciddi bir sürtünmeye yol açtı. Neredeyse her gün birden çok build hatası alıyorduk. Çoğu zaman küçük bir kütüphanenin, bizim doğrudan kullanmadığımız bir fonksiyonundaki zafiyet yüzünden tüm deploy süreci duruyordu.

# Örnek bir CI/CD pipeline adımı (pseudo-code)
security_scan:
  stage: test
  script:
    - npm audit --production --audit-level=high
    - if [ $? -ne 0 ]; then
        echo "Kritik veya Yüksek seviye bağımlılık zafiyetleri bulundu. Build durduruluyor!";
        exit 1;
      fi
  allow_failure: false # Burası kritik, build'i durdurur

Bu yaklaşımın en büyük avantajı, güvenlik açıklarının prod ortamına sızma riskini minimize etmesidir. Her hata anında görülür ve düzeltilmesi gerekir. Ancak dezavantajları da azımsanmayacak kadar çoktur. Geliştiriciler, sürekli kırılan build’ler yüzünden motivasyon kaybedebilir ve güvenlik tarayıcılarına karşı bir tür “körlük” geliştirebilirler. Ayrıca, her bağımlılık zafiyetinin acil bir risk oluşturmadığı durumlar da vardır, ancak bu yaklaşım bunları ayırt etmez.

Uyarı Vermek: Esneklik mi, Risk Ertelemesi mi?

Build’i durdurmak yerine sadece uyarı vermek, daha esnek bir yaklaşımdır. Bu senaryoda, bağımlılık tarayıcıları zafiyetleri tespit eder, raporlar, ancak CI/CD pipeline’ı çalışmaya devam eder. Amaç, geliştiricilere bilgi vermek ve güvenlik ekiplerine izlenecek bir liste sunmaktır.

Kendi yan ürünlerimden birinde, başlangıçta bu yöntemi tercih ettim. Geliştirme hızını kesmek istemiyordum ve “Medium” veya “Low” seviye zafiyetlerin anında build’i durdurmasını gereksiz buluyordum. İlk başta her şey yolundaydı; ara sıra gelen uyarıları gözden geçiriyor, kritik olanları düzeltiyorduk. Ancak aylar geçtikçe biriken onlarca orta seviye CVE beni ciddi düşündürdü. Bu zafiyetlerin çoğu, birbiriyle ilişkili olmasa da, toplamda ciddi bir risk oluşturmaya başlamıştı.

# Örnek bir CI/CD pipeline adımı (pseudo-code)
security_scan:
  stage: test
  script:
    - npm audit --production --audit-level=info
    - echo "Bağımlılık zafiyetleri tespit edildi. Lütfen raporu inceleyin."
  allow_failure: true # Burası önemli, build'i durdurmaz

Bu yaklaşımın temel avantajı, geliştirme akışının kesintiye uğramamasıdır. Geliştiriciler, güvenlik sorunları hakkında bilgilendirilir ancak acil bir düzeltme yapmaları gerekmez. Bu, özellikle hızlı teslimat gerektiren projelerde tercih edilebilir. Ancak risk, bu uyarıların zamanla göz ardı edilmesi ve güvenlik borcunun birikmesidir. Zamanla, biriken uyarılar bir “gürültü” haline gelir ve gerçekten kritik bir zafiyet bile bu gürültü içinde kaybolabilir.

Kritiklik Seviyeleri ve Otomatik Düzeltmelerin Rolü

Tüm bağımlılık zafiyetleri aynı değildir. “Critical”, “High”, “Medium”, “Low” gibi kritiklik seviyeleri, bir zafiyetin potansiyel etkisini ve istismar edilebilirliğini gösterir. Bu ayrıma göre aksiyon almak, daha dengeli bir yaklaşım sunar. Örneğin, bir “Low” seviye zafiyet için build’i durdurmak yerine, sadece “Critical” veya “High” seviyelerde durdurmak daha mantıklı olabilir.

Güvenlik politikasını bu kritiklik seviyelerine göre ayarlamak, dengeli bir orta yol sunar. Sadece “Critical” ve “High” seviye CVE’lerde build’i durdurma kararı aldığınızda, build hatası sayısını belirgin biçimde azaltır ve geliştiricilerin daha az “false positive” ile uğraşmasını sağlarsınız. “Medium” ve “Low” seviye zafiyetler için ise ayrı bir güvenlik panosu oluşturup bunları düzenli olarak takip etmek mantıklıdır.

Otomatik bağımlılık güncelleyicileri de bu süreçte önemli bir rol oynar. Bu botlar, yeni bir güvenlik açığı tespit edildiğinde, bağımlılığın yamalı bir sürümüne otomatik olarak pull request oluşturabilir. Bu, geliştiricilerin manuel olarak takip etmesi gereken iş yükünü önemli ölçüde azaltır. Ancak, otomatik güncellemelerin her zaman sorunsuz çalışmadığını, bazen breaking change’lere veya uyumsuzluklara yol açabileceğini de göz önünde bulundurmak gerekir. Bu yüzden, otomatik güncellemelerin de CI/CD pipeline’ından geçip test edilmesi şarttır.

Benim Tercihim: Durum Bazlı Hibrit Bir Yaklaşım

Yıllar içinde edindiğim tecrübeler, “tek beden herkese uyar” bir çözümün bağımlılık güvenliğinde olmadığını gösterdi. Her projenin, her ekibin ve her organizasyonun kendine özgü risk toleransı ve geliştirme kültürü var. Bu yüzden, benim net pozisyonum, durum bazlı, hibrit bir yaklaşımdır.

Yüksek riskli bir finansal platformda uygulanacak strateji ile kişisel bir yan üründe uygulanacak strateji tamamen farklı olur. Bankacılık gibi alanlarda en ufak bir zafiyet bile büyük finansal ve itibar riskleri taşır; bu yüzden “Critical” ve “High” seviye zafiyetlerde build’i durdurmak çoğu zaman zorunludur. Daha az riskli bir yan üründe ise “Medium” seviye zafiyetleri sadece izleyip periyodik olarak manuel müdahale etmek yeterli olabilir.

Hibrit yaklaşımımı genellikle şu adımlarla uyguluyorum:

  1. Kritik Seviye Zafiyetlerde Build’i Durdur: “Critical” veya “High” olarak işaretlenmiş tüm CVE’ler için CI/CD pipeline’ını kesinlikle durdururum. Bu, en acil ve potansiyel olarak en yıkıcı riskleri elimine etmenin en hızlı yoludur.
  2. Orta ve Düşük Seviye Zafiyetlerde Uyarı Ver ve Takip Et: “Medium” ve “Low” seviye zafiyetler için build’i durdurmam. Bunun yerine, bu zafiyetleri ayrı bir güvenlik panosunda (örneğin, Slack entegrasyonu veya Jira ticket’ları aracılığıyla) takip ederim. Bu, geliştiricilerin akışını bozmadan bilgi sahibi olmalarını sağlar.
  3. Otomatik Güncellemeleri Kullan: Dependabot veya Renovate gibi araçları kullanarak, yamalı bağımlılık sürümlerini otomatik olarak entegre etmeye çalışırım. Bu pull request’ler, diğer kod değişiklikleri gibi test pipeline’ından geçer.
  4. Periyodik Manuel İnceleme ve Risk Değerlendirmesi: Her çeyrekte veya önemli bir sürümden önce, biriken “Medium” ve “Low” seviye zafiyetleri manuel olarak gözden geçiririm. Bu inceleme sırasında, zafiyetin projenin gerçek kullanım senaryosunda ne kadar risk oluşturduğunu değerlendiririm. Bazen bir zafiyet, bizim kullandığımız modülü etkilemeyebilir ve bu durumda istisna listesine eklenebilir.

Bu yaklaşım, güvenlik ile geliştirme hızı arasında hassas bir denge kurmayı sağlar. Hem en kritik riskleri bertaraf ederiz hem de geliştiricilerin sürekli build hatalarıyla boğuşmasını engelleriz. Yazılım Geliştirmede Observability konusundaki deneyimlerim, bu takip süreçlerinin ne kadar önemli olduğunu bana defalarca gösterdi. Aynı şekilde, CI/CD Pipeline Güvenliği üzerine yazdığım bir yazıda da bu otomasyon adımlarını detaylandırmıştım.

Uygulamada Dikkat Edilmesi Gerekenler ve Metrikler

Hibrit bir bağımlılık güvenliği stratejisi uygularken dikkat edilmesi gereken birkaç önemli nokta var. İlk olarak, “false positive” oranını iyi yönetmek gerekir. Bazen güvenlik tarayıcıları, gerçekte bir risk oluşturmayan durumlar için uyarı verebilir. Bu gibi durumlarda, zafiyetin projenin bağlamında gerçekten istismar edilebilir olup olmadığını dikkatlice değerlendirmek ve gerekiyorsa istisna listesine eklemek önemlidir. Ancak bu istisnaları çok dikkatli kullanmak ve dokümante etmek şarttır.

Belirli bir kütüphanenin “Medium” seviye bir CVE’si uzun süre tekrar eden bir “false positive” uyarısına dönüşebilir. Sürekli aynı uyarıyı görmek, ekibin diğer kritik uyarılara karşı duyarsızlaşmasına neden olur. Çoğu zaman zafiyet, sizin kullanım senaryonuzda risk oluşturmaz; çünkü zafiyetli fonksiyon hiç çağrılmıyordur (reachability). Bu tür durumlarda, bir karar defteri oluşturup neden istisna edildiğini açıkça belirtmek hayati önem taşır.

İkinci olarak, güvenlik performansını ölçmek için doğru metrikleri takip etmek gerekir. Benim takip ettiğim bazı temel metrikler şunlar:

  • Sprint Başına Yeni Zafiyet Sayısı: Her sprint sonunda tespit edilen yeni “Critical” ve “High” seviye zafiyetlerin sayısı.
  • Kritik Zafiyet Çözüm Süresi (Mean Time To Resolve - MTTR): “Critical” veya “High” olarak işaretlenen bir zafiyetin tespit edilmesinden çözülmesine kadar geçen ortalama süre.
  • Güvenlik Nedeniyle Build Başarısızlık Oranı: Toplam build sayısına oranla güvenlik zafiyetleri nedeniyle başarısız olan build’lerin yüzdesi.
  • Güvenlik Borcu (Security Debt): Biriken “Medium” ve “Low” seviye zafiyetlerin toplam sayısı.
Metrik Adı Tanım Hedef Değer
Yeni Kritik Zafiyet / Sprint Her sprintte ortaya çıkan yeni Critical/High zafiyet sayısı < 1
Kritik Zafiyet MTTR Critical/High zafiyetin tespitinden düzeltilmesine kadar geçen süre < 24 saat
Güvenlik Build Başarısızlık Oranı Güvenlik taraması nedeniyle başarısız olan build’lerin oranı < %5
Güvenlik Borcu (Medium/Low) Biriken Medium/Low zafiyetlerin toplam sayısı < 50 (proje bazlı değişir)

Bu metrikler, zaman içindeki eğilimleri görmemizi ve güvenlik duruşumuzun iyileşip iyileşmediğini anlamamızı sağlar. Örneğin, kritik zafiyet çözüm süresi artıyorsa, bu, güvenlik ekibi veya geliştiriciler üzerinde bir iş yükü sorunu olduğunu gösterebilir.

Son olarak, SBOM (Software Bill of Materials) oluşturmak ve sürdürmek, bağımlılık güvenliğinde şeffaflık sağlar. SBOM, projenizde kullanılan tüm bağımlılıkların ve bunların sürümlerinin bir listesidir. Bu liste, yeni bir CVE yayınlandığında, hangi projelerinizin etkilendiğini hızlıca tespit etmenize yardımcı olur.

Sonuç

Bağımlılık güvenliği, modern yazılım projelerinin kaçınılmaz bir gerçeği. Build’i durdurmak veya sadece uyarı vermek arasında bir seçim yapmak, projenin bağlamına, risk toleransına ve ekibin kültürüne bağlıdır. Benim tecrübelerime göre, en etkili yol, bu iki yaklaşımı dengeli bir şekilde birleştiren hibrit bir strateji uygulamaktır.

Kritik zafiyetlerde sıfır tolerans gösterirken, daha düşük seviyeli sorunlar için esneklik sağlamak, hem güvenliği sürdürmek hem de geliştirme hızını korumak için anahtardır. Unutmayalım ki, güvenlik bir yolculuktur ve sürekli adaptasyon ile öğrenmeyi gerektirir. Önemli olan, riskleri anlamak, doğru araçları kullanmak ve ekibin güvenlik bilincini yüksek tutmaktır.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

Sıkça Sorulanlar

Bu makale ile ilgili okurların sorduğu yaygın sorular.

Bağımlılık güvenliği taramasını CI pipeline'ına nasıl ekleyebilirim ve hangi araçları tercih ettim?
Ben CI sürecime öncelikle `npm audit` ve `yarn audit` komutlarını bir adım olarak ekledim. Bu komutları `npm ci` sonrası çalıştırıp çıktıyı JSON formatına çeviriyorum, ardından bir küçük Node script'iyle yüksek riskli (high/critical) CVE'leri filtreliyorum. Eğer bir yüksek risk tespit edilirse build'i durduruyorum; düşük riskli ise sadece bir uyarı veriyorum. Ayrıca `snyk test` ve `dependabot` gibi bulut tabanlı hizmetleri de paralel olarak entegre ettim; bu araçlar PR'lerde otomatik güncellemeler öneriyor ve raporları Slack'e gönderiyor. Böyle bir kombinasyon, hem yerel hem de bulut taraflı denetimi tek bir akışta tutmamı sağladı.
Build'i durdurmak yerine sadece uyarı vermek risk yönetiminde ne gibi avantaj ve dezavantajlar sağladı?
Ben build'i tamamen durdurduğumda, ekip aniden bir güvenlik açığı yüzünden durma noktasına geliyor ve teslim tarihleri uzuyor; bu, özellikle sprint içinde acil bir özelliği tamamlamamız gerektiğinde büyük bir engel oluyor. Uyarı vermek ise riskin farkında olmamızı sağlarken, geliştirme akışını kesintiye uğratmıyor; böylece kritik bir güvenlik sorunu olsa bile, geçici bir çözümle ilerleyip daha sonra planlı bir güncelleme yapabiliyoruz. Dezavantajı, uyarıyı göz ardı eden bir ekip kültürü oluşabilir ve yüksek riskli bir zafiyet uzun süre prodüksiyona kalabilir. Bu yüzden uyarı seviyesini bir SLA'ya bağlayıp, belirli bir süre içinde düzeltme planı oluşturmak benim için dengeyi kurdu.
Yüksek riskli CVE'ler tespit edildiğinde hatayı nasıl ele aldım ve kaç deneme sonrası karar verdim?
Bir yüksek riskli CVE tespit ettiğimde önce ilgili paketin en son sürümünü ve changelog'ını inceliyorum; çoğu zaman sadece bir patch sürümü sorunu çözüyor. Eğer bu sürüm mevcut değilse, geçici bir fork oluşturarak güvenlik düzeltmesini manuel ekliyorum ve test ortamında bütün entegrasyon testlerini çalıştırıyorum. Genellikle önce doğrudan güncellemeyi deniyorum; o işe yaramazsa fallback olarak fork yoluna gidiyorum. İki yaklaşım da sorunu çözmezse, ilgili paketin maintainer'ına bir issue açıyor ve kritik olduğundan build'i durduruyorum. Böyle bir yaklaşım, zaman kaybını minimize ederken acil durumları da kontrol altında tutuyor.
‘npm audit’ sonuçlarını görmezden gelmek ya da sadece ‘warning’ olarak kabul etmek doğru mu? Genel kanı ne kadar yanıltıcı?
Ben `npm audit` sonuçlarını tamamen görmezden gelmekten kaçınıyorum; raporlar, transitive bağımlılıkların da güvenlik durumunu gösteriyor ve bu, çoğu zaman gözden kaçan bir zafiyeti ortaya çıkarıyor. Sadece ‘warning’ olarak kabul etmek, düşük riskli paketlerde işe yarasa da, yüksek riskli bir CVE’nin uyarı seviyesinde kalması, ekip içinde bir güvenlik yanılgısına yol açabilir. Genel kanı, “uyarı yeterli” diyerek riskin hafifletilebileceği düşüncesi, özellikle dışa açık hizmetlerde yanıltıcıdır. Ben her ‘high’ ya da ‘critical’ bulguyu bir aksiyon maddesi olarak ele alıyor, en az bir sprint içinde düzeltme planı oluşturuyorum; bu, güvenlik kültürünü gerçekçi tutmamı sağlıyor.
ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Yorumlar

Sunucu Taraflı AI Moderasyon

Yorumlar sunucuda yapay zeka ile denetlenir ve kalıcı olarak saklanır.

?
0/2000

Sunucu taraflı AI denetim

✉️ Ücretsiz · Spam yok · İstediğin an çık

Yeni yazılardan haberdar olun

Yeni içerikler ve teknik notlar e-postanıza gelsin.

  • 📌
    Haftanın en iyisi Sadece okumaya değer tek yazı
  • 🔧
    Alet çantası Bu hafta kullandığım araçlar
  • 🧠
    Perde arkası Blog'a girmeyen notlar

Spam yapmıyoruz. İstediğiniz zaman ayrılabilirsiniz. · Sadece Umami (self-hosted, Google yok) ile takip.

Okuma İstatistikleriniz

0

Yazı Okundu

0dk

Okuma Süresi

0

Gün Serisi

-

Favori Kategori

İlgili Yazılar