Dependency Confusion: Bağımlılık Karışıklığı Tedarik Zinciri Saldırısı
Şirket içi paket adınızı saldırgan herkese açık registry'ye daha yüksek sürümle yükleyince paket yöneticisi yanlışlıkla onu çeker ve kod çalışır. Dependency confusion nasıl çalışır, npm pip maven'da neden olur ve scoped paket, private registry, lockfile ile nasıl kapatılır.
Hızlı cevap: Dependency confusion (bağımlılık karışıklığı), bir saldırganın şirketinizin iç kullanıma özel paket adını (örneğin
sirket-ortak-kutuphane) herkese açık registry'ye (npm, PyPI, Maven Central) daha yüksek bir sürüm numarasıyla yüklemesidir. Paket yöneticisi varsayılan olarak "en yüksek sürümü al" davrandığı ve iç registry ile genel registry'yi aynı anda sorguladığı için, build sırasında saldırganın public paketini iç paketin yerine çeker ve içindeki kod derleme/kurulum anında çalışır. Korunma: iç paketleri scope/namespace altına alın, paket yöneticisini iç paketleri yalnız özel registry'den çekecek biçimde yapılandırın, iç adlarınızı public registry'de önden rezerve edin, lockfile ve bütünlük (integrity hash) kullanın, bir SCA aracıyla bağımlılıkları sürekli denetleyin.
Modern yazılımın çoğu üçüncü taraf paketlerden oluşur ve bu, tedarik zinciri saldırılarının en verimli hedefidir. 2021'de güvenlik araştırmacısı Alex Birsan, yalnız paket-adı tahminiyle onlarca büyük şirketin build sistemine kod çalıştırdı; yöntem "dependency confusion" olarak anıldı ve hâlâ yaygın bir açıktır. Bu rehber mekanizmayı, neden paket yöneticilerinde doğal olarak oluştuğunu ve bir kurumun bunu kökten nasıl kapatacağını anlatır.
Saldırı nasıl çalışır
Şirketler, yalnız kendi içlerinde kullandıkları iç paketler yazar ve bunları özel (private) bir registry'den çeker. Sorun, paket yöneticisinin iç registry ile genel (public) registry'yi birlikte sorgulaması ve çoğu zaman en yüksek sürüm numarasını kazanan olarak seçmesidir.
Adım adım: saldırgan bir şekilde iç paket adını öğrenir (sızan package.json, açık kaynak katkıları, hata mesajları, iş ilanları). Sonra aynı adı herkese açık registry'ye, örneğin 99.0.0 gibi absürt yüksek bir sürümle yükler. Kurumun build sistemi paketi çözerken public'teki 99.0.0'ı iç registry'deki gerçek 1.4.2'den daha yeni görür ve onu çeker. Paketin kurulum betiği (npm postinstall, Python setup.py) build anında çalışır; artık saldırganın kodu sizin CI/CD ortamınızda, çoğu zaman kimlik bilgilerine ve kaynak koda erişerek koşar. CI/CD hattının güvenliğini CI/CD pipeline DevSecOps yazımızda ayrıntılı ele aldık.
Neden paket yöneticilerinde doğal oluşur
| Ekosistem | Varsayılan davranış | Karışıklık nedeni |
|---|---|---|
| npm (Node.js) | scope'suz ad hem public hem private aranır | public'teki yüksek sürüm kazanır |
| pip (Python) | ek index " extra" olarak eklenir, ikisi de aranır | public'teki yüksek sürüm çekilebilir |
| Maven/Gradle (Java) | repository sırası + sürüm çözümü | yanlış repo'dan yüksek sürüm |
| NuGet (.NET) | birden çok feed birlikte | public feed'den çekim |
Ortak kök neden aynıdır: paket yöneticisi "aynı ada sahip iki kaynak varsa hangisi?" sorusuna güvenlik değil, sürüm-yüksekliği ile cevap verir ve iç/dış ayrımını zorlamaz. Bu bir "açık" değil, yanlış-yapılandırılabilen bir varsayılandır.
Korunma: iç paketi dışarıdan ayır
Kök çözüm, iç paketlerin asla public registry'den çekilememesini garanti etmektir. Katmanlı önlemler:
Birincisi, scope/namespace. İç paketleri bir scope altına alın (npm'de @sirket/paket) ve o scope'u yalnız özel registry'ye bağlayın; böylece public'e aynı scope'la paket yükleyemezler. İkincisi, registry yapılandırması: paket yöneticisini iç adları yalnız private registry'den çekecek biçimde ayarlayın (npm'de scope-registry eşlemesi, pip'te tek güvenilir index + diğerlerini kapatma). Üçüncüsü, ad rezervasyonu: iç paket adlarınızı (veya scope'unuzu) public registry'de önceden, boş bir paketle rezerve edin ki saldırgan o adı alamasın. Dördüncüsü, lockfile + integrity hash: package-lock.json, poetry.lock gibi kilit dosyaları beklenen sürümü ve kriptografik hash'i sabitler; beklenmedik bir kaynak/hash build'i durdurur. Beşincisi, SCA (yazılım bileşen analizi): bağımlılıkları sürekli tarayıp bilinen açıkları ve şüpheli paketleri işaretler. SCA'nın SAST/DAST içindeki yerini SAST, DAST, IAST ve SCA seçim matrisi yazımızda inceledik.
CI/CD ve build ortamı sertleştirme
Dependency confusion'ın asıl zararı build ortamında kod çalıştırmaktır, bu yüzden build ortamını da sertleştirmek gerekir. Build konteynerleri dışa giden ağ erişiminde kısıtlanmalı (yalnız onaylı registry'lere), kurulum betiklerinin (postinstall vb.) çalışması gözden geçirilmeli, build sırrı ve token'lar en az-yetki ilkesiyle verilmeli ki bir paket çalışsa bile elde edeceği şey sınırlı olsun. Bir SBOM (yazılım malzeme listesi) tutmak, hangi sürümün nereden geldiğini denetlenebilir kılar. Bulut tabanlı build hatları için bulut sızma testi yazımız ve API yüzeyi için API güvenliği OWASP API Top 10 yazımız tamamlayıcıdır.
KAOS ve DSET yaklaşımı
DSET olarak tedarik zinciri değerlendirmelerinde kurumun iç paket adlarının dışarıya sızıp sızmadığını (public registry'de rezerve mi, saldırgan alabilir mi), paket yöneticisi yapılandırmasının iç/dış ayrımını zorlayıp zorlamadığını ve build ortamının izole olup olmadığını inceleriz. Geliştirdiğimiz KAOS aracı keşif sırasında sızan package.json/bağımlılık adlarını ve açık registry yapılandırmalarını işaretler, çünkü saldırı çoğu zaman tek bir sızmış iç-paket adıyla başlar. Bulguyu doğrulamadan "kritik" demez, abartı yapmayız. Kurumunuzun yazılım tedarik zincirini değerlendirmek için Ankara Hacettepe Teknokent bünyesindeki ekibimizle DSET ile iletişime geçin.
Sık sorulan sorular
İç paketlerimiz zaten private registry'de, yine de risk var mı? Evet, eğer paket yöneticisi iç registry ile public registry'yi birlikte sorguluyorsa. Private registry'de olması yetmez; paket yöneticisini iç adları YALNIZ private registry'den çekecek biçimde yapılandırmanız, scope kullanmanız ve iç adları public'te rezerve etmeniz gerekir. Aksi halde public'e yüklenen yüksek-sürümlü sahte paket yine kazanır.
Lockfile kullanıyorum, bu beni korur mu? Lockfile önemli bir katmandır ama tek başına yetmez. Kilit dosyası beklenen sürümü ve hash'i sabitler, yani mevcut bağımlılıklar için çözümü dondurur. Ancak yeni bir bağımlılık eklenirken veya lockfile yeniden üretilirken karışıklık yine oluşabilir. Lockfile'ı scope, registry yapılandırması ve ad rezervasyonuyla birlikte kullanın.
Küçük bir projeyim, hedef olur muyum? Dependency confusion otomatiktir ve ad-temellidir; saldırgan büyük-küçük ayırmadan toplu olarak iç-paket adlarını public'e yükleyip bekler. İç paket kullanan her ekip hedeftir. İyi haber, korunması ucuz ve kalıcıdır: doğru registry yapılandırması ve scope bir kez kurulunca sürekli korur.
Kaynaklar
- Alex Birsan, "Dependency Confusion" (2021) özgün araştırması.
- OWASP, yazılım tedarik zinciri güvenliği ve bağımlılık riskleri.
- npm, PyPI ve Maven resmî belgeleri: scope, index ve repository yapılandırması.
- DSET blog: CI/CD pipeline DevSecOps sızma testi ve SAST, DAST, IAST ve SCA seçim matrisi.
Kimliğinizi doğrulayın
Yetkilendirilmiş erişim alanı. Tüm giriş denemeleri kayıt altına alınır.