Katı İçerik Güvenliği Politikası (İGP) ile siteler arası komut dosyası kullanımını (XSS) azaltın

Lukas Weichselbaum
Lukas Weichselbaum

Tarayıcı Desteği

  • Chrome: 52..
  • Kenar: 79..
  • Firefox: 52..
  • Safari: 15.4.

Kaynak

Siteler arası komut dosyası çalıştırma (XSS), bir web uygulamasına kötü amaçlı komut dosyaları yerleştirme kullanmaya devam ediyor.

İçerik Güvenliği Politikası (İGP) XSS'yi azaltmaya yardımcı olan ek bir güvenlik katmanıdır. CSP'yi yapılandırmak için: Content-Security-Policy HTTP üstbilgisini bir web sayfasına ekleyin ve Kullanıcı aracısının söz konusu sayfa için hangi kaynakları yükleyebileceğini kontrol eder.

Bu sayfada, XSS'yi azaltmak için nonce veya hash'lere dayalı bir CSP'nin nasıl kullanılacağı açıklanmaktadır. yaygın olarak kullanılan, ana makine izin verilenler listesi tabanlı ve genellikle sayfadan ayrılan CSP'ler yerine çoğu yapılandırmada atlanabildikleri için XSS'e maruz kalırlar.

Anahtar terim: Tek seferlik rastgele sayısı, bir öğeyi işaretlemek için kullanabileceğiniz rastgele bir sayıdır. <script> etiketi güvenilir olarak işaretlendi.

Anahtar terim: Karma işlevi, girdi dönüşümünü gerçekleştiren matematiksel bir işlevdir. değerini karma adı verilen sıkıştırılmış sayısal bir değere dönüştürebilirsiniz. Karma oluşturma işlemi uygulamak için (örneğin, SHA-256) kullanarak <script> etiketi güvenilir olarak işaretlendi.

Noce veya karmalara dayalı bir İçerik Güvenliği Politikası genellikle katı CSP değerleridir. Bir uygulama katı bir CSP kullandığında, HTML'yi bulan saldırganlar yerleştirme hataları, genellikle bunları tarayıcıyı Güvenli olmayan bir dokümanda kötü amaçlı komut dosyaları. Bunun nedeni yalnızca katı CSP'dir Oluşturulan doğru tek seferlik rastgele sayı değerine sahip, karma oluşturma işlemi uygulanmış komut dosyalarına veya Bu nedenle, saldırganlar doğru tek seferlik rastgele sayı bilmeden komut dosyasını çalıştıramaz. temel alabilir.

Neden katı bir CSP kullanmalısınız?

Sitenizde zaten script-src www.googleapis.com gibi görünen bir İGP varsa siteler arası için etkili olmayacaktır. Bu tür CSP'ler İzin verilenler listesi CSP. Çok fazla özelleştirme gerektirirler ve atlanabilir.

Kriptografik nonce'lara veya hash'lere dayalı katı CSP'ler bu tehlikelerden kaçınır.

Katı CSP yapısı

Temel bir katı İçerik Güvenliği Politikası, aşağıdaki HTTP yanıtlarının birini kullanır başlıklar:

Duyarlı olmayan sıkı CSP

Content-Security-Policy:
  script-src 'nonce-{RANDOM}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';
Tek seferlik olmayan katı bir CSP'nin işleyiş şekli.

Karma tabanlı katı CSP

Content-Security-Policy:
  script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';

Aşağıdaki özellikler bunun gibi bir İGP'yi "katı" yapar ve dolayısıyla güvenlidir:

  • Noce 'nonce-{RANDOM}' veya 'sha256-{HASHED_INLINE_SCRIPT}' karmaları kullanıyor sitenin geliştiricisinin güvendiği <script> etiketlerini belirtmek için Kullanıcının tarayıcısı.
  • 'strict-dynamic' Böylece, tek seferlik rastgele veya karma tabanlı bir CSP'yi otomatik olarak dağıtma güvenilir bir komut dosyasının oluşturduğu komut dosyalarının yürütülmesine olanak tanır. Bu ayrıca çoğu üçüncü taraf JavaScript kitaplığının ve widget'ının kullanılmasını engeller.
  • URL izin verilenler listelerini temel almadığından yaygın CSP atlamaları.
  • Satır içi etkinlik işleyiciler veya javascript: gibi güvenilmeyen satır içi komut dosyalarını engeller. URI'lar.
  • Flash gibi tehlikeli eklentileri devre dışı bırakmak için object-src ürününü kısıtlar.
  • base-uri ürününü, <base> etiketlerinin yerleştirilmesini engelleyecek şekilde kısıtlar. Bu durum, saldırganların göreli URL'lerden yüklenen komut dosyalarının konumlarını değiştirmesini engelleyebilir.
ziyaret edin.

Katı bir İGP benimseyin

Katı bir CSP benimsemek için şunları yapmanız gerekir:

  1. Uygulamanızın tek seferlik mi yoksa karma tabanlı CSP mi ayarlaması gerektiğine karar verin.
  2. Katı CSP yapısı bölümünden CSP'yi kopyalayıp ayarlayın bir yanıt başlığı olarak kullanabilirsiniz.
  3. Kalıpları kaldırmak için HTML şablonlarını ve istemci tarafı kodunu yeniden düzenleme uyumlu değildir.
  4. CSP'nizi dağıtın.

Daha fazla bilgi için Lighthouse'u (--preset=experimental işaretiyle birlikte sürüm 7.3.0 ve sonraki sürümler) En İyi Uygulamalar denetimi Bu süreç boyunca sitenizde İGP bulunup bulunmadığını ve bu içeriğin CSP olup olmadığını XSS'ye karşı etkili olacak kadar katı olmalıdır.

Deniz feneri
  yaptırım modunda hiçbir İGP bulunamadığını belirten uyarı bildirimi.
Sitenizde CSP yoksa Lighthouse bu uyarıyı gösterir.

1. Adım: Tek seferlik veya karma tabanlı bir CSP'ye ihtiyacınız olup olmadığına karar verin

Katı CSP'nin iki türü şu şekilde işler:

Tek seferlik rastgele sayı tabanlı CSP

Ortalama olmayan bir CSP ile çalışma zamanında rastgele bir sayı oluşturur ve bunu CSP'nizi tanımlama ve sayfanızdaki tüm komut dosyası etiketiyle ilişkilendirmeniz gerekir. Bir saldırgan çalıştıramaz. Bunun nedeni, bunların doğru rastgele sayıyı tahmin edebilir. Bu yalnızca telefon araması üreten tahmin edilemez ve her yanıt için çalışma zamanında yeni oluşturulur.

Sunucuda oluşturulan HTML sayfaları için tek seferlik rastgele olmayan bir CSP kullanın. Bu sayfalarda her yanıt için yeni bir rastgele sayı oluşturabilirsiniz.

Karma tabanlı CSP

Karma tabanlı bir CSP için, her satır içi komut dosyası etiketinin karma değeri CSP'ye eklenir. Her komut dosyasının farklı bir karması vardır. Saldırganlar kötü amaçlı bir dosya içeremez veya çalıştıramaz komut dosyası yükleyebilirsiniz. Çünkü bu komut dosyasının karmasının gerekli olan CSP'dir.

Statik olarak sunulan HTML sayfaları veya önbelleğe alındı. Örneğin, tek sayfalık web için karma tabanlı bir CSP kullanabilirsiniz. Angular, React veya diğerleri gibi çerçevelerle oluşturulmuş diğer sunucu tarafında oluşturulmadan statik olarak sunulur.

2. Adım: Katı bir CSP belirleyin ve komut dosyalarınızı hazırlayın

CSP ayarlarken birkaç seçeneğiniz vardır:

  • Yalnızca rapor modu (Content-Security-Policy-Report-Only) veya yaptırım modu (Content-Security-Policy). Yalnızca rapor modunda, CSP çalışır, dolayısıyla sitenizdeki hiçbir şey bozulamaz, ancak hatalar görebilir ve her tür içeriği raporlayabilir. Yerel olarak, CSP'nizi ayarlamanın önemi yoktur, çünkü her iki mod da emin olun. Yaptırım modu, aşağıdakileri yapmanıza yardımcı olabilir: kaynaklarınız olacaktır çünkü bir kaynağı engellemek, sayfa bozuk görünüyor. Salt rapor modu işlemin ilerleyen aşamalarında en yararlı hale gelir (5. adıma bakın).
  • Üstbilgi veya HTML <meta> etiketi. Yerel geliştirme için <meta> etiketi daha fazla olabilir CSP'nizde ayarlamalar yapmak ve sitenizi nasıl etkilediğini hızla görmek için uygundur. Ancak:
    • Daha sonra, CSP'nizi üretime dağıtacağınız zaman bir HTTP üstbilgisi ekleyin.
    • İGP'nizi salt rapor modunda ayarlamak isterseniz bunu bir üst bilgisine eklenmelidir. Bunun nedeni, CSP meta etiketleri salt rapor modunu desteklememesidir.

Seçenek A: Tek seferlik rastgele sayı tabanlı İGP

Aşağıdaki Content-Security-Policy HTTP yanıtını ayarlayın başlık ekleyin:

Content-Security-Policy:
  script-src 'nonce-{RANDOM}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';

CSP için tek seferlik rastgele sayı oluşturma

Tek seferlik rastgele sayı, sayfa yükleme başına yalnızca bir kez kullanılan rastgele bir sayıdır. Tek seferlik rastgele olmayan CSP, yalnızca saldırganlar tek seferlik rastgele sayı değerini tahmin edemediğinde XSS'nin etkisini azaltabilir. CEVAP CSP tek seferlik rastgele sayısı:

  • Kriptografik olarak güçlü bir rastgele değer (ideal olarak 128 bitten fazla uzunlukta)
  • Her yanıt için yeni oluşturulur
  • Base64 olarak kodlanmış

Sunucu tarafı çerçevelere CSP tek seferlik rastgele sayısının nasıl ekleneceğiyle ilgili bazı örnekleri burada bulabilirsiniz:

const app = express();

app.get('/', function(request, response) {
  // Generate a new random nonce value for every response.
  const nonce = crypto.randomBytes(16).toString("base64");

  // Set the strict nonce-based CSP response header
  const csp = `script-src 'nonce-${nonce}' 'strict-dynamic'; object-src 'none'; base-uri 'none';`;
  response.set("Content-Security-Policy", csp);

  // Every <script> tag in your application should set the `nonce` attribute to this value.
  response.render(template, { nonce: nonce });
});

<script> öğelerine nonce özelliği ekleyin

Ortalama olmayan bir CSP ile her <script> öğesi, rastgele tek seferlik rastgele sayıyla eşleşen bir nonce özelliğine sahip CSP başlığında belirtilen değer. Tüm komut dosyaları aynı tek seferlik rastgele sayı. İlk adım, bu özellikleri tüm komut dosyalarına eklemektir. Böylece CSP bunlara izin verir.

Seçenek B: Karma Tabanlı CSP Yanıt Başlığı

Aşağıdaki Content-Security-Policy HTTP yanıtını ayarlayın başlık ekleyin:

Content-Security-Policy:
  script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';

Birden fazla satır içi komut dosyası için söz dizimi aşağıdaki gibidir: 'sha256-{HASHED_INLINE_SCRIPT_1}' 'sha256-{HASHED_INLINE_SCRIPT_2}'

Kaynaklı komut dosyalarını dinamik olarak yükleme

CSP karmaları tüm tarayıcılarda yalnızca satır içi komut dosyaları için desteklendiğinden, tüm üçüncü taraf komut dosyalarını satır içi bir komut dosyası kullanarak dinamik olarak yüklemeniz gerekir. Kaynaklı komut dosyalarına yönelik karmalar tarayıcılar arasında iyi bir şekilde desteklenmez.

Komut dosyalarınızı satır içine nasıl yerleştireceğinize dair örnek.
CSP tarafından izin verildi
<script>
  var scripts = [ 'https://example.org/foo.js', 'https://example.org/bar.js'];

  scripts.forEach(function(scriptUrl) {
    var s = document.createElement('script');
    s.src = scriptUrl;
    s.async = false; // to preserve execution order
    document.head.appendChild(s);
  });
</script>
Bu komut dosyasının çalışmasını sağlamak için satır içi komut dosyasının karmasını hesaplamanız gerekir ve bunu {HASHED_INLINE_SCRIPT} yer tutucusu içerir. Karma sayısını azaltmak için tüm satır içi öğeleri birleştirebilirsiniz tek bir komut dosyasına dönüştürmenize olanak tanır. Bunun nasıl uygulandığını görmek için şuraya bakın: örnek ve kodunu içerir.
CSP tarafından engellendi
<script src="https://example.org/foo.js"></script>
<script src="https://example.org/bar.js"></script>
Yalnızca satır içi komut dosyalarına karma oluşturma işlemi uygulanabileceğinden CSP bu komut dosyalarını engeller.

Komut dosyası yüklemeyle ilgili dikkat edilmesi gereken noktalar

Satır içi komut dosyası örneği, s.async = false foo öğesinin bar öncesinde yürütüldüğü, bar önce yüklenir. Bu snippet'te, s.async = false , komut dosyaları yüklenirken ayrıştırıcıyı engellemez, çünkü dinamik bir şekilde eklenir. Ayrıştırıcı, yalnızca komut dosyaları yürütülürken durur; async komut dosyası için de geçerlidir. Ancak bu snippet'le unutmayın:

  • Komut dosyalarından biri veya her ikisi, doküman tamamlanmadan önce yürütülebilir indiriliyor. Belli bir zaman dilimi içinde dokümanın komut dosyaları yürütülür, önce DOMContentLoaded etkinliğini bekleyin bazı işaretler var. Bu durum, komut dosyaları yeterince erken indirilemiyorsa sayfada daha önceki önceden yükleme etiketlerini kullanın.
  • defer = true hiçbir şey yapmaz. İhtiyacınız varsa Gerektiğinde komut dosyasını manuel olarak çalıştırın.

3. Adım: HTML şablonlarını ve istemci tarafı kodunu yeniden düzenleyin

Satır içi etkinlik işleyiciler (ör. onclick="…", onerror="…") ve JavaScript URI'leri (<a href="javascript:…">), komut dosyalarını çalıştırmak için kullanılabilir. Bu, XSS hatası bulan saldırganlar, bu tür HTML'leri yerleştirebilir ve kötü amaçlı yazılım JavaScript'e dokunun. Tek seferlik veya karma tabanlı bir CSP, bu tür işaretlemelerin kullanımını yasaklar. Siteniz bu kalıplardan herhangi birini kullanıyorsa bunları daha güvenli olacak şekilde yeniden düzenlemeniz gerekir. sağlayabilir.

Önceki adımda CSP'yi etkinleştirdiyseniz İGP ihlallerini şurada görebilirsiniz: CSP uyumsuz bir kalıbı her engellediğinde konsola geri yüklenir.

Chrome Developer Console&#39;daki İGP ihlal raporları.
Engellenen kod için konsol hataları.

Bu sorunu çoğu durumda kolayca çözebilirsiniz:

Satır içi etkinlik işleyicileri yeniden düzenleme

CSP tarafından izin verildi
<span id="things">A thing.</span>
<script nonce="${nonce}">
  document.getElementById('things').addEventListener('click', doThings);
</script>
CSP, JavaScript kullanılarak kaydedilen etkinlik işleyicilere izin verir.
CSP tarafından engellendi
<span onclick="doThings();">A thing.</span>
CSP, satır içi etkinlik işleyicileri engeller.

javascript: URI'sını yeniden düzenle

CSP tarafından izin verildi
<a id="foo">foo</a>
<script nonce="${nonce}">
  document.getElementById('foo').addEventListener('click', linkClicked);
</script>
CSP, JavaScript kullanılarak kaydedilen etkinlik işleyicilere izin verir.
CSP tarafından engellendi
<a href="javascript:linkClicked()">foo</a>
CSP JavaScript'i engeller: URI'lar.

eval() JavaScript'inizden kaldırın

Uygulamanız JSON dizesi serileştirmelerini JS'ye dönüştürmek için eval() kullanıyorsa nesnelerinde bu tür örnekleri JSON.parse() olarak yeniden düzenlemelisiniz. Bu da daha hızlı şekilde ayarlayabilirsiniz.

Tüm eval() kullanımlarını kaldıramıyorsanız yine de rastgele olmayan katı bir değer ayarlayabilirsiniz CSP'dir, ancak 'unsafe-eval' İGP anahtar kelimesini kullanmanız gerekir. Bu da daha az güvenlidir.

Bu katı CSP'de bunları ve yeniden düzenlemeyle ilgili daha fazla örnek bulabilirsiniz. codelab:

4. Adım (İsteğe bağlı): Eski tarayıcı sürümlerini desteklemek için yedek ekleyin

Tarayıcı Desteği

  • Chrome: 52..
  • Kenar: 79..
  • Firefox: 52..
  • Safari: 15.4.

Kaynak

Eski tarayıcı sürümlerini desteklemeniz gerekiyorsa:

  • strict-dynamic kullanımı, daha önceki öğeler için yedek olarak https: eklenmesini gerektirir sürümlerinde yer alır. Bunu yaptığınızda:
    • strict-dynamic özelliğini destekleyen tüm tarayıcılar https: yedeğini yoksayar, bu nedenle politikanın gücünü azaltmaz.
    • Eski tarayıcılarda, harici olarak sağlanan komut dosyaları yalnızca HTTPS kaynağı. Bu, katı bir CSP'den daha az güvenli olsa da javascript: URI'larının yerleştirilmesi gibi bazı yaygın XSS nedenlerini önler.
  • Çok eski (4+ yıl) tarayıcı sürümleriyle uyumluluğu sağlamak için unsafe-inline yedek olarak kullanılabilir. Son tarayıcıların tümü unsafe-inline talimatını yoksayar CSP tek seferlik rastgele sayı veya karma varsa.
Content-Security-Policy:
  script-src 'nonce-{random}' 'strict-dynamic' https: 'unsafe-inline';
  object-src 'none';
  base-uri 'none';

5. Adım: İGP'nizi dağıtın

CSP'nizin yerel geliştirme ortamınızdan yararlanmak istiyorsanız CSP'nizi hazırlık aşamasına, ardından kendi üretim ortamı:

  1. (İsteğe bağlı) CSP'nizi Content-Security-Policy-Report-Only üstbilgisi. Salt rapor modu, önce üretimde yeni bir İGP gibi zarar verebilecek bir değişikliği test etmeden önce CSP kısıtlamalarını uygulamaya başlayabilirsiniz. Yalnızca rapor modunda İGP'niz uygulamanızın davranışını etkilemesine rağmen tarayıcı yine de konsol hataları oluşturacaktır ve ihlal raporları, İGP'nizle uyumlu olmayan kalıplarla karşılaştığında Böylece son kullanıcılarınız açısından neyin sorun olabileceğini görebilirsiniz. Daha fazla Reporting API'ye göz atın.
  2. İGP'nizin son kullanıcılarınız için sitenizi bozmayacağından emin olduğunuzda Content-Security-Policy yanıt başlığını kullanarak CSP'nizi dağıtın. Biz CSP'nizi sunucu tarafında bir HTTP başlığı kullanarak ayarlamanızı öneririz. <meta> etiketinden daha güvenlidir. Bu adımı tamamladıktan sonra İGP'niz nasıl koruyacağını daha iyi anlayacaksınız.
ziyaret edin.

Sınırlamalar

Katı bir CSP genellikle yardımcı olabilir. Çoğu durumda CSP saldırı yüzeyini önemli ölçüde küçülterek javascript: URI'leri gibi tehlikeli kalıpları reddetmektedir. Ancak, reklamın türüne göre içeren ('strict-dynamic' içeren veya içermeyen) CSP'ler, CSP'nin uygulamanızı korumadığı durumlar şunlardır:

  • Bir komut dosyasını tek seferlik rastgele eklerseniz, ancak doğrudan gövdeye veya Bu <script> öğesinin src parametresi.
  • Dinamik olarak oluşturulan komut dosyalarının konumlarına yerleştirme varsa (document.createElement('script')) (tüm kitaplık işlevleri dahil) , bağımsız değişkenlerinin değerlerine göre script DOM düğümü oluşturan Bu jQuery'nin .html() yanı sıra .get() ve jQuery'de .post() < 3.0.
  • Eski AngularJS uygulamalarında şablon yerleştirme işlemi varsa. Bir saldırgan bir AngularJS şablonuna eklenebilen isteğe bağlı JavaScript yürütün.
  • Politika 'unsafe-eval', eval() konumuna eklemeler içeriyorsa setTimeout() ve nadiren kullanılan diğer birkaç API.

Geliştiriciler ve güvenlik mühendisleri bu tür durumlara özellikle dikkat etmelidir: emin olun. Ayrıntılı bilgiyi Bu durumlara İçerik Güvenliği Politikası: Sağlamlaştırma ve Azaltma Arasındaki Başarılı Kargaşa bölümünden ulaşabilirsiniz.

Daha fazla bilgi