Subresource Integrity (SRI) ile Harici Kaynakların Bütünlüğünü Kontrol Etmek

Tuğsan Ünlü
4 min readAug 16, 2020

--

Front-End uygulamalarımıza üçüncü parti kaynaklar dâhil etmek istediğimizde ekseriyetle NPM veya Yarn gibi paket yönetim sistemlerini kullanıyoruz. Fakat bazen de bu kaynakları doğrudan kaynağın geliştiricisi veya kimi aracıların (Cloudflare vb.) sağladığı barındırma hizmetleri üzerinden projelerimize dâhil ediyoruz. Projelerin ihtiyaçlarına göre her iki yöntemin de avantajları ve dezavantajları var. Fakat en çok tercih edilme nedenlerine bakıldığında ilkinde kapsamlı bir sürüm takibi yapmak istemek ikincisinde ise bir CDN hizmetini ücretsiz olarak kullanmak başat rol oynuyor.

cdnjs’den alınan UIkit kaynağı

Üstteki örneği inceleyelim. UIKit CSS çatısına ait fonksiyonların bulunduğu JavaScript dosyasını Cloudflare’in bir hizmeti olan cdnjs’den alarak sayfamıza bağladık diyelim. Bu sayede dünyanın dört bir yanında sunucuları bulunan Cloudflare’in CDN hizmetinden faydalanmış ve uygulamamızı kullananlara hızlı bir deneyim yaşatmış olacağız.

Fakat bir yandan bu kaynakla ilgili barındırma sorumluluklarını da kendi üstümüzden Cloudflare’a devretmiş olacağız. Yarın kötü niyetli kişiler tarafından Cloudflare sunucularına bir şekilde erişilip ilgili dosyanın içeriği değiştirilse zararlı bir dosyayı projemize dâhil ederek hayatımıza devam edecek ve belki farkında olmadan sömürüleceğiz.

2014'teki Gigya vakası bununla ilgili yaşanmış en büyük örneklerden. Aralarında Forbes, Ferrari, Yemek Sepeti gibi markaların yer aldığı Gigya servisinin kullanıcıları, Suriye Elektronik Ordusu tarafından yapılan saldırıdan etkilendiler. Tek yaptıkları ise hizmet aldıkları Gigya tarafından barındırılan bir JavaScript dosyasını sayfalarına bağlamalarıydı. Suriye Elektronik Ordusu, onlarca web sitesinde zafiyet aramaktansa hepsinin kullandığı ortak bir serviste zafiyet buldu ve günün sonunda onlarca web sitesi bu saldırıdan etkilendi.

Subresource Integrity

Subresource Integrity (alt kaynak bütünlüğü) bu soruna çözüm olarak geliştirilmiş bir özellik. Harici kaynaktan sayfamıza bir dosya bağladığımızda ilgili dosyanın özetini de (hash) beraberinde belirtmemize olanak tanıyıp karşılaştırma yapıyor. Bu sayede uzak sunucudaki dosya bir şekilde değiştirildiğinde hash’i de değişiyor ve ilk aldığımız hash ile uyuşmayacağı için dosyanın yüklenmesi tarayıcı tarafından engelleniyor.

cdnjs’den SRI ile birlikte alınan UIkit kaynağı

Üstteki örneği yeniden inceleyelim. İlkinden farklı olarak integrity alanını görüyoruz. Bu alanda ilgili JavaScript dosyasının hash‘inin alındığı algoritma ve hemen akabinde dosya hash’inin Base64 ile kodlanmış hâlini görüyoruz.

Subresource Integrity için Hash Oluşturma

Buraya kadarkiler harici bir kaynağı kullanırken yapacaklarımıza dairdi. Fakat bu kaynağı başkalarının kullanımına sunan da biz olabiliriz. O zaman potansiyel kullanıcılara dosyamızla beraber karşılaştırma için kullanılacak bir hash sunmalıyız. İlk olarak basit bir fonksiyondan oluşan index.js dosyamızı oluşturalım.

index.js

Şimdi bu dosyanın hash’ine ihtiyacımız var. Hash oluşturmak için farklı yöntemler mevcut. Yazının kaynaklar kısmında bazı bağlantılar paylaşacağım. Fakat OpenSSL kütüphanesi Unixish işletim sistemlerinde hâlihazırda kurulu olduğu için bana en pratiği o geliyor. OpenSSL ile dosyanın hash’ini çıkaralım.

openssl ile SRI için hash oluşturma

Üstteki komutla ilk olarak index.js dosyasını okuduk. Pipe (|) yardımıyla çıktıları bir sonraki araca yönlendirerek sha512 algoritmasıyla çıkardığımız dosyanın hash’ini Base64 ile kodladık. Akabinde kopyaladığımız nihai çıktıyı integrity alanına hash algoritması-kodlanmış hashformatında yapıştırdık.

Harici kaynakların çağrılmasında SRI kullanımı

index.js dosyasını bir HTML dosyası içerisinde çağırıp tarayıcının konsolundan davranışını gözlemlediğimizde fonksiyonumuzun istediğimiz şekilde çalıştığını görüyoruz.

It works!

Bu defa index.js dosyasına yeni bir satır ekleyelim fakat integrity alanını değiştirmeden davranışını gözlemleyelim.

Kod enjekte edilmiş index.js

Failed to find a valid digest in the ‘integrity’ attribute for resource ‘http://localhost:8001/index.js' with computed SHA-256 integrity ‘fTWx2biPHTV1oJeoltQMO5lgUJ6txLrLVlScKNWe33E=’. The resource has been blocked.

Görüldüğü gibi integrity alanındaki hash değeri dosya içeriğiyle eşleşmediği için tarayıcı kaynağın sayfada çalıştırılmasını engelledi ve It works! çıktısını alamadık.

Subresource Integrity kullanımıyla ilgili hem harici kaynakları tüketen hem de onları üretenler olarak bir hassasiyetin ve refleksin oluşması gerekiyor Gigya benzeri vakaların yaşanmaması için.

Tüketici tarafında özellikle jsDelivr, cdnjs gibi SRI sunan servisler tercih edilebilir. Zaten popüler CDN servislerinin çoğunda bu özellik mevcut. Üretenler tarafında ise dosyalarla birlikte hash paylaşmayı alışkanlık hâline getirmek gerekiyor. Elbette her zaman dosya hash’lerini kullanıcının kendisinin oluşturma imkânı var ama henüz tarayıcılar tarafından zorunlu tutulan bir özellik olmadığından kullanıcı tercihine bırakıldığında ihmal edilmesi muhtemel bir efor olarak gözüküyor. Ayrıca kendi projelerimiz içerisindeki kaynaklar için tekrar tekrar hash oluşturma külfeti, Webpack Subresource Integrity gibi Webpack eklentileri sayesinde otomatize edilebilir.

Kaynaklar

https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
https://report-uri.com/home/sri_hash
https://www.srihash.org
https://www.independent.co.uk/life-style/gadgets-and-tech/news/syrian-electronic-army-hack-hits-sites-using-gigya-but-all-data-safe-9887503.html
https://www.netsparker.com/blog/web-security/subresource-integrity-sri-security/

Görsel: Psychic Donut

--

--

Tuğsan Ünlü
Tuğsan Ünlü

Written by Tuğsan Ünlü

Senior Application Architect, Technical Product Owner @Akbank — tugsanunlu.com

No responses yet