NPM Audit ile NPM Paketlerinin Güvenlik Zafiyetlerini Denetlemek ve Gidermek

Tuğsan Ünlü
5 min readJul 18, 2020

Girizgah

Geçtiğimiz hafta sonu semantik versiyonlama ve NPM’de nasıl kullanıldığına dair yazmıştım. Bu hafta ise yine hakkında Türkçe kaynağa rastlayamadığım bir başka konu NPM Audit üzerine yazmak istedim. Neden böyle bir araca ihtiyacımız olduğundan bahsederek hemen başlayayım.

Önceleri

Front-End uygulamalarında NPM veya Yarn gibi paket yönetim sistemleri kullanmaya başlamadan evvel üçüncü parti bir eklenti kullanmak istediğimizde karşımıza kabaca iki yöntem çıkıyordu. İlki, eklentinin kaynak kodunu indirip doğrudan proje içerisinde bir dizine koymaktı. İkincisi ise kaynak kodu proje içerisine dahil etmeden bir CDN servisinden faydalanarak ihtiyaç duyulan sayfaya bağlamaktı.

Fakat her iki durumda da güvenlikle ilgili endişeler doğuyordu. Şöyle ki, diyelim tüm HTTP trafiğinin üzerinden aktığı üçüncü parti bir HTTP istemcisini projemize bu yöntemlerden birini kullanarak dahil ettik. Üzerinden altı ay geçti ve projemiz sorunsuz şekilde çalışmaya devam etti. Ya da biz öyle sandık. İstemciyi projeye dahil ettiğimizin ertesi günü bulunan bir güvenlik zafiyetiyle altı aydır ruhumuz duymadan sömürülüyor olabilirdik. Üstelik istemcinin geliştiricisi bu açığı çoktan kapatmışken.

Arkada tüm bu olaylar yaşanırken bizi uyarabilecek bir sistem yoktu. Kısmen Acunetix benzeri analiz araçları bu konularda çözümler sunabiliyordu fakat onlar da maliyeti göz önüne alındığında her hacimdeki projenin sahip olabileceği araçlar değildi. Genellikle bu zafiyetlerin sosyal olarak denetlenmesi ve giderilmesi gerekiyordu. Çoğu zaman da maalesef ihmal ediliyordu.

Şimdilerde

Paket yönetim sistemleriyle birlikte daha pratik çözümlere kavuştuk. Çünkü artık elimizde projemizde kullandığımız tüm üçüncü parti paketleri versiyonlarıyla birlikte görebildiğimiz dökümler (package.json ve package-lock.json dosyaları) var. Bunlarla birlikte paketler de merkezi bir yerden yönetilince nispeten işler kolaylaştı.

NPM Audit, projemiz içerisindeki paketlerin bilinen güvenlik zafiyetleri konusunda bizi bilgilendiren ve istersek bu zafiyetleri giderebilen bir komut satırı aracı.

Kullanım

Nasıl kullanıldığıma bakmak için hızlıca bir proje oluşturalım ve akabinde eski yeni birtakım paketler dahil edelim projeye.

npm init -y

Axios’un 0.18.0 versiyonunda bir güvenlik zafiyeti olduğunu bildiğim için onu da özellikle kuruyorum.

npm install webpack js-cookie axios@0.18.0 firebase localforage
kurulum çıktısı

Kurulumlar tamamlandıktan hemen sonra bir paketimizde zafiyet olduğu bilgisini alıyoruz. NPM Audit ile detaylarına bakalım.

npm audit

Yukarıda kurduğumuz 5 paket ve onların bağımlılıklarıyla birlikte toplamda 418 paketin tarandığını ve zafiyet içeren 1 paketin bulunduğunu görüyoruz.

npm audit çıktısı

Oluşturulan raporda zafiyetin şiddeti ve muhtemel sonuçları hakkında bilgiler alıyoruz. NPM’de zafiyetler low (düşük), moderate (orta), high (yüksek) ve critical (kritik) olmak üzere dört seviyede ele alınıyor. Denetlemelerimizi bu seviyelere göre filtreleyebilmemiz mümkün. Örneğin aşağıdaki komut, proje içerisindeki high ve üstündeki seviyelerde (high ve critical) yer alan zafiyetleri kontrol edecektir.

npm audit --audit-level=high

Tekrar rapora dönersek axios paketinin orta seviyede ve paketin sağladığı servisleri kullanım dışı (denial of service) bırakabilecek bir zafiyet barındırdığını görüyoruz. Ayrıca sitede daha fazla bilgi olduğu belirtiliyor. Tıklayıp gidelim.

npmjs.com’daki zafiyet sayfası

npmjs.com üzerindeki sayfada zafiyeti kimin bildirdiğinden ne zaman çözüldüğüne, teknik detaylarından zafiyetten etkilenen ve etkilenmeyen versiyonlara kadar birçok bilgi paylaşılıyor. Bizim için en önemli kısmı ise zafiyetin çözümü için önerilen eylem. Paketi 0.18.1 veya daha güncel bir versiyona yükseltmemiz öneriliyor. Hemen yapıp akabinde yeniden NPM Audit’i çalıştıralım.

npm install axios@0.18.1 && npm audit

Görüldüğü gibi artık zafiyet içeren bir paketimiz bulunmuyor.

Otomatik Zafiyet Gidermek

Fakat bunu her paket için tek tek elle mi yapmalıyız? Sonuçta zafiyet ve çözümü için yapılması gereken eylem ortada. NPM Audit bu zafiyetleri otomatik olarak giderebiliyor. Test etmek için axios paketini yeniden zafiyetli 0.18.0 versiyonuna indirelim ve hemen arkasından NPM Audit’i “fix” özelliğiyle çalıştıralım.

npm install axios@0.18.0 && npm audit fix

Çıktıdan görülebileceği gibi az önce elle yaptığımız versiyon yükseltme işlemini NPM Audit bizim için yaptı.

NPM Audit’in “fix” özelliğinin şöyle bir handikapı var. Bir paketin zafiyetli olduğunu bilseniz dahi her zaman ilgili yükseltmeyi derhal yapmamanız gerekebiliyor. Çünkü farklı bir paket çalışmak için sizin kullandığınız tam da o zafiyetli versiyona ihtiyaç duyuyor olabilir. Ayrıca yükseltilecek paket sayısı her zaman böyle az olmayabilir. Aynı anda 20 paketi birden yükselttiğinizde muhtemelen uygulama içerisindeki işleyişte birbiriyle konuşan paketlere temas etmiş olacaksınız ve uygulamanızda nedenini anlayamadığınız birçok hata ve yan etki oluşacak.

O yüzden süreci tamamıyla otomatikleştirmektense versiyon notlarını okuyarak ve neyi neden yükselttiğimizden haberdar olarak ilerlemek sonradan baş ağrıtmaması adına daha pratik bir çözüm olabiliyor. Zaten bu denetlemeleri sıklıkla yaptığımızda zafiyetli paket sayılarımız yönetilemeyecek, dokümanları okunamayacak kadar artmıyor.

CI/CD Süreçlerinde Denetlemeleri Otomatikleştirmek

NPM Audit’i pratik bir şekilde kullanıp zafiyetleri giderdik. Fakat her defasında elle mi çalıştıracağız? Ya unutursak? Bu nokta da diğer birçok komut satırı aracında olduğu gibi CI/CD süreçlerindeki pipeline’lara kolayca entegre edebiliyoruz NPM Audit’i. Bu sayede NPM Audit’in projemiz teste veya canlıya çıkmadan evvel çalışmasını sağlayabiliyoruz.

Hemen onun da bir örneğini yapalım.

Bash Script’teki $? komutu son çalıştırılan komutun çıkış kodunu (exit status) verir bize. Aşağıdaki komut ile ilk olarak NPM Audit’i çalıştırıp çıktısını /dev/null‘a göndererek ekrana basmamasını sağlıyoruz. Sonrasında da $? ile ne çıktı verdiğine bakıyoruz.

npm audit > /dev/null; echo $?

Son çalıştırdığımız “fix” özelliği sayesinde şu anda zafiyetli paketimiz olmadığından “0" çıktısını alacağız. 0, çıkış kodlarında her şeyin yolunda olduğunu gösterir.

Paketin sürümünü düşürüp yeniden çalıştıralım.

npm install axios@0.18.0 && npm audit > /dev/null; echo $?

Bu defa “1” çıktısını alacağız.

Böylece NPM Audit’i bir pipeline’a eklediğimizde zafiyetli paketimiz varsa, yani çıkış kodu olarak “0" dışında herhangi bir şey alıyorsak sürecin kesilmesini, yoksa uygulamamızın teste veya canlıya çıkmasını sağlayabiliriz. Hatta rapor çıktısını ilgili geliştiriciye e-posta göndererek raporlamak gibi senaryolar da kurgulayabiliriz. Bunun için NPM Audit’in parseable parametresinden faydalanılabilir.

npm audit --parseable

Önceki çıktılardaki tabloyu üzerinde işlem yapılabilir bir metin hâline getirecektir. Benzer şekilde --json parametresiyle de çıktı JSON’a dönüştürülebilir.

Sonuç

Bir proje içerisinde yüzlerce farklı paket kullanıyoruz. Bunlara tek tek hakim olabilmek maalesef şu anki geliştirme ortamlarımızda -en azından yakın gelecekte- pek mümkün gözükmüyor. O yüzden NPM Audit çok faydalı bir yardımcı araç. Özellikle CI/CD süreçlerine dahil edildiğinde olası tehlikeler için geliştiricileri uyararak derhal tedbir almalarını sağlıyor.

Ben önceki yazıda olduğu gibi bunda da NPM üzerinden anlattım ve örneklendirdim. Fakat Yarn Audit’in de kullanımı ufak farklılıkları olmasıyla birlikte NPM Audit’ten çok farklı değil. O yüzden yazdıklarımın büyük çoğunluğu her iki ekosistem içerisinde de geçerli.

Kaynaklar

https://docs.npmjs.com/cli/audit
https://docs.npmjs.com/auditing-package-dependencies-for-security-vulnerabilities
https://blog.npmjs.org/post/173719309445/npm-audit-identify-and-fix-insecure

--

--