Üçüncü taraf CDN'lerden veya harici kaynaklardan komut dosyaları, stil sayfaları, yazı tipleri ya da resimler yüklerken Alt Kaynak Bütünlüğü (HTML'de integrity ve CSS'de integrity() url()) ile bunların kriptografik bütünlüğünü doğrulayın, çapraz kaynak kimlik bilgisi işlemeyi (crossorigin ve cross-origin()) yapılandırın ve giden Referer üstbilgilerini (referrerpolicy ve referrer-policy()) kısıtlayın. Belge düzeyinde İçerik Güvenliği Politikası ve giden bağlantı izin verilenler listeleri için Web Güvenliği ve Bağlantı İzin Verilenler Listeleri ile giden ağ bağlantılarını kısıtlama başlıklı makaleleri inceleyin.
1. Sabit öğeler için kriptografik bütünlük özetleri oluşturma
Alt Kaynak Bütünlüğü (SRI), tarayıcının yalnızca baytları uygulamanız tarafından beyan edilen kriptografik karma ile eşleşen harici öğeleri yürütmesini veya oluşturmasını sağlar.
- Özetleri derleme veya yayınlama sırasında hesaplayın, hiçbir zaman canlı güvenilmeyen yanıtlardan hesaplamayın: Derleme veya yayınlama adımınız sırasında bilinen iyi yerel öğe baytlarından bütünlük karmaları oluşturun (veya paket yazarı tarafından yayınlanan resmi özeti kopyalayın) ve bunları HTML, CSS veya JavaScript'inize sabit kodlayın. Kendi
integritykarma değerini hesaplamak için çalışma zamanında tarayıcıda üçüncü taraf URL'si getirmeyin. Bu işlem, uzak sunucunun döndürdüğü tüm baytlara güvenir ve SRI'yi geçersiz kılar. - Varsayılan olarak
sha384-kullan: Bütünlük meta verilerinisha384-(önerilen varsayılan),sha512-veyasha256-kullanarak<algorithm>-<base64-digest>olarak biçimlendirin. - Harici alt kaynakları sabit, sürümlü URL'lere sabitleyin: Üçüncü taraf öğelerine her zaman, sitenizi sessiz tedarik zinciri değişikliklerine maruz bırakan ve uzak dosya güncellenir güncellenmez SRI'yi bozan değişken kayan URL'ler (
latest/app.min.js) yerine sabit, sürüme sabitlenmiş veya içerik adresli URL'ler (https://cdn.example.com/ui@2.4.0/app.min.jsgibi) kullanarak referans verin. Yerinde güncellenen değişken bir üçüncü taraf komut dosyası (ör. tedarikçi firma analiz etiketi) yüklemeniz gerekiyorsa bu URL'deintegrityparametresini atlayın ve bunun yerine İçerik Güvenliği Politikası (strict-dynamic/tek seferlik rastgele sayılar) veya iframe korumalı alanıyla kısıtlayın. - Bir uç nokta birden fazla geçerli yük sunabildiğinde birden fazla özeti boşlukla ayırma: SRI'yi destekleyen tüm tarayıcılar
sha256-,sha384-vesha512-'yi uygular. Bir URL, bilinen birkaç iyi yükten birini meşru olarak döndürebiliyorsa (ör. A/B testi, aşamalı CDN sunumu veya içerik anlaşmalı derleme sırasında) aynı algoritmanın birden fazla özetini boşlukla ayırarak listeleyin (ör.integrity="sha384-variantA... sha384-variantB..."). Tarayıcı, mevcut en güçlü algoritmanın listelenen özetlerinden herhangi biriyle eşleşirse yanıtı kabul eder. - Çapraz kaynak alt kaynaklarını CORS başlıklarıyla sunun: Tarayıcılar, çapraz kaynak yanıtının bütünlüğünü yalnızca CORS tarafından okunabilir olduğunda (anonim istekler için
Access-Control-Allow-Origin: *veya kimlik bilgisi içeren istekler içinAccess-Control-Allow-Credentials: trueile tam istek kaynağı) doğrulayabilir.
# Generate a sha384- SRI hash at build time from a known-good local file
printf "sha384-%s\n" "$(openssl dgst -sha384 -binary app.min.js | openssl base64 -A)"
// Build-time / tooling helper (Node.js 19+, Deno, Bun) to compute an SRI string from known-good local bytes
export async function computeIntegrityMetadata(bytes) {
const rawBytes =
typeof bytes === 'string' ? new TextEncoder().encode(bytes) : bytes;
const digestBuffer = await crypto.subtle.digest('SHA-384', rawBytes);
const binary = Array.from(new Uint8Array(digestBuffer), (b) =>
String.fromCharCode(b),
).join('');
return `sha384-${btoa(binary)}`;
}
2. Güvenli HTML komut dosyaları, stil sayfaları ve önceden yüklemeler
Belge düzeyinde bir Referrer-Policy: strict-origin-when-cross-origin HTTP yanıt başlığı ayarlayın (veya <head> içine <meta name="referrer" content="strict-origin-when-cross-origin"> ekleyin). Böylece, istek başına yönlendiren değiştiriciyi atlayan tüm alt kaynaklar veya CSS url(), çapraz kaynak isteklerde hassas yol ve sorgu parametrelerini kaldırmaya devam eder.
Ardından, harici <script>, <link rel="stylesheet">, <link rel="preload"> ve <link rel="modulepreload"> öğelerinde her zaman integrity, crossorigin ve referrerpolicy öğelerini birlikte ayarlayın:
integrity="sha384-...": Yanıt baytları beklenen özetle eşleşmiyorsa kaynağın yürütülmesini veya uygulanmasını engeller (engellenen bir<link rel="stylesheet">içinlinkElement.sheet,nullolarak kalır ve birerroretkinliği tetiklenir).crossorigin="anonymous"(herkese açık CDN öğeleri için önerilen varsayılan) veyacrossorigin="use-credentials":integrity, çapraz kaynaklı bir kaynakta ayarlandığında gereklidir.crossoriginparametresinin atlanması, tarayıcının kaynağıno-corsmodunda getirmesine (karma doğrulaması yapılamayan opak bir yanıt oluşturur) ve kaynağı engellemesine neden olur.referrerpolicy="no-referrer"(üçüncü taraf CDN'ler için önerilen varsayılan) veyareferrerpolicy="strict-origin-when-cross-origin":Refereristek başlığındaki kaynak veya yol bilgilerinin üçüncü taraf ana makineye sızmasını önlemek için doküman yönlendiren politikasını geçersiz kılar.
<!-- Document-level baseline referrer policy in <head> (or via Referrer-Policy HTTP header) -->
<meta name="referrer" content="strict-origin-when-cross-origin" />
<!-- External stylesheet with SRI, anonymous CORS, and no referrer -->
<link
rel="stylesheet"
href="https://cdn.example.com/ui@2.4.0/styles.css"
integrity="sha384-bs0EksOYBbU/g0IAHMXbSyH1Mgw83GKn+EZlSI+VE+zVchXmSbLwhVLrPzsOWnc5"
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<!-- External script with SRI, anonymous CORS, and no referrer -->
<script
src="https://cdn.example.com/ui@2.4.0/bundle.min.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
fetch() ile harici alt kaynakları programatik olarak getirirken eşleşen integrity, mode, credentials ve referrerPolicy seçeneklerini iletin (özet uyuşmazlığı, TypeError ile vaadi reddeder):
const response = await fetch('https://cdn.example.com/ui@2.4.0/manifest.json', {
integrity: 'sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC',
mode: 'cors',
credentials: 'omit',
referrerPolicy: 'no-referrer',
});
3. url() değiştiricileriyle CSS resimlerini, yazı tiplerini ve içe aktarılan stil sayfalarını güvenli hale getirme
CSS url() istek değiştiricileri (cross-origin(), referrer-policy() ve integrity()); background-image, content, mask-image, border-image-source, filter, @font-face src ve @import kuralları dahil olmak üzere CSS ile yüklenen kaynakların getirme modunu, yönlendiren üstbilgisini ve alt kaynak bütünlüğü doğrulamasını doğrudan CSS'den kontrol eder:
| Değiştirici işlevi | Bağımsız değişken söz dizimi ve izin verilen değerler | Amaç |
|---|---|---|
cross-origin(<ident>) |
Tırnak içine alınmamış anahtar kelime: anonymous (önerilen varsayılan) veya use-credentials |
CORS kullanarak CSS kaynağını getirir ve kimlik bilgilerinin gönderilip gönderilmeyeceğini kontrol eder. Çapraz kaynak CSS kaynaklarında her zaman integrity() ile birlikte ekleyin. |
referrer-policy(<ident>) |
Tırnak içine alınmamış anahtar kelime: no-referrer (üçüncü taraf öğeler için önerilen varsayılan), strict-origin-when-cross-origin, origin, same-origin, strict-origin, origin-when-cross-origin, no-referrer-when-downgrade veya unsafe-url |
Bu CSS isteği için doküman yönlendiren politikasını geçersiz kılar. |
integrity("<string>") |
Tırnak içine alınmış dize: "sha384-<base64>" (veya boşlukla ayrılmış özetler "sha384-... sha384-...") |
Alınan CSS kaynağını oluşturmadan veya uygulamadan önce beklenen kriptografik özete göre doğrular. |
url() değiştiricileri oluştururken aşağıdaki CSS söz dizimi ve güvenlik kurallarına uyun:
- URL dizesini
url("...")içine alın: İstek değiştiriciler yalnızcaurl(...)içindeki URL tırnak içine alınmış bir<string>olduğunda geçerlidir (tırnak içine alınmamış URL'ler değiştiricileri kullanamaz). - Her niteleyici türünü
url()başına en fazla bir kez belirtin:url("..." ...)içindecross-origin(),referrer-policy()veintegrity()niteleyicilerini istediğiniz sırayla birleştirebilirsiniz ancak aynı niteleyici türünü iki kez tekrarlamak (ör. ikiintegrity()niteleyicisi) geçersizdir. Birden fazla karma sağlamak için bunları tek birintegrity("sha384-... sha384-...")dizesi içinde boşlukla ayırın. - Çapraz kaynak
integrity()ilecross-origin(anonymous)her zaman birlikte kullanılmalıdır:@font-facesrcvemask-imagevarsayılan olarak anonimcorsmodunda getirilirkenbackground-image,content,border-image-sourceve@importvarsayılan olarakno-corsmoduna (karma doğrulaması yapılamayan opak bir yanıt oluşturur) ve harici SVGfiltervarsayılan olaraksame-originmoduna (çapraz kaynak URL'leri tamamen engeller) ayarlanır.cross-origin(anonymous)(veyacross-origin(use-credentials)) eklemek, her CSS mülkünde tutarlı CORS doğrulaması sağlar. - Değiştiricileri
@importve@font-facekurallarındaurl("...")içine yerleştirin:cross-origin(),referrer-policy()veintegrity()'yiurl("..." ...)içinde tutarkenformat("woff2")vetech(...)gibi yazı tipi tanımlayıcılarınıurl(...)dışında tutun.
@import url(
"https://cdn.example.com/theme@1.2.0/tokens.css"
cross-origin(anonymous)
referrer-policy(no-referrer)
integrity("sha384-bs0EksOYBbU/g0IAHMXbSyH1Mgw83GKn+EZlSI+VE+zVchXmSbLwhVLrPzsOWnc5")
);
@font-face {
font-family: "BrandSans";
src: url(
"https://cdn.example.com/fonts@1.0.0/brand-sans.woff2"
cross-origin(anonymous)
referrer-policy(no-referrer)
integrity("sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC")
) format("woff2");
font-display: swap;
}
.verified-graphic {
background-image: url(
"https://cdn.example.com/media@1.0.0/badge.svg"
cross-origin(anonymous)
referrer-policy(no-referrer)
integrity("sha384-Iw/0p59dP96nGTzHvf2XIfqcBwBW7RM6JfOij8uZxyg5azfNaOOUW8SQy6H/hU91")
);
}
Yedek stratejiler
Temel hedefiniz henüz CSS url() istek değiştiricilerini (cross-origin(), referrer-policy() veya integrity()) desteklemiyorsa alt kaynakların işlevsel ve korumalı kalması için belge düzeyindeki politikaları basamaklı CSS bildirimleriyle birleştirin:
- Tarayıcılar arası SRI gerektiğinde CSS
@importyerine HTML<link rel="stylesheet">tercih edin:<link rel="stylesheet">üzerindekisubresource-integrityvereferrer-policytüm tarayıcılarda yaygın olarak kullanılabildiğinden, her tarayıcıda bütünlük doğrulamasının zorunlu kılınması gerektiğinde harici stil sayfalarını@importyerine<link rel="stylesheet" href="..." integrity="sha384-..." crossorigin="anonymous" referrerpolicy="no-referrer">ile yükleyin. - 2. adımdaki belge düzeyinde
Referrer-Policybaşlığına veya<meta name="referrer">öğesine güvenin: CSSurl()içindereferrer-policy()özelliğini desteklemeyen tarayıcılarda, belge düzeyindeReferrer-Policy: strict-origin-when-cross-originbaşlığı veya<meta name="referrer" content="strict-origin-when-cross-origin">öğesi, çapraz kaynak CSS isteklerindeki hassas yol ve sorgu parametrelerini otomatik olarak kaldırır. Progresif geliştirme için ayrı CSS bildirimlerini basamaklama:
url("..." ...)içindeki bir değiştiriciyi tanımayan tarayıcılar, CSS ayrıştırma sırasında bildirimin tamamını siler. Önce basit birurl("..."), ardındancross-origin()vereferrer-policy()bildirimi (bu iki değiştiriciyi destekleyen ancakintegrity()'yi desteklemeyen tarayıcılar için) ve son olarakintegrity("sha384-...")dahil tam bildirimi beyan edin:- Doğrulanmamış bir
url()değerini asla aynı virgülle ayrılmış@font-facesrclistesine koymayın:src: url("font.woff2" cross-origin(anonymous) integrity("sha384-...")), url("font.woff2");değerini tek birsrctanımlayıcısına yazmak, çalışma zamanında Alt Kaynak Bütünlüğü'nü atlar. Bir CDN,integrity()kontrolünü geçemeyen, üzerinde oynanmış bir yazı tipi sunarsa tarayıcı bunu yükleme hatası olarak değerlendirir ve otomatik olarak virgülle ayrılmış ikinciurl("font.woff2")değerine geri döner. Ayrısrc:bildirimler kullanmak, destekleyen tarayıcıların CSS ayrıştırma sırasında doğrulanmamış bildirimin üzerine yazmasını ve çalışma zamanında değiştirilmiş yazı tiplerini engellemesini sağlar.
@font-face { font-family: "BrandSans"; /* 1. Parse-time fallback for browsers without url() modifier support */ src: url("https://cdn.example.com/fonts@1.0.0/brand-sans.woff2") format("woff2"); /* 2. Parse-time fallback for browsers supporting cross-origin() and referrer-policy() */ src: url( "https://cdn.example.com/fonts@1.0.0/brand-sans.woff2" cross-origin(anonymous) referrer-policy(no-referrer) ) format("woff2"); /* 3. Full protection in browsers supporting cross-origin(), referrer-policy(), and integrity() */ src: url( "https://cdn.example.com/fonts@1.0.0/brand-sans.woff2" cross-origin(anonymous) referrer-policy(no-referrer) integrity("sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC") ) format("woff2"); font-display: swap; } .verified-graphic { background-image: url("https://cdn.example.com/media@1.0.0/badge.svg"); background-image: url( "https://cdn.example.com/media@1.0.0/badge.svg" cross-origin(anonymous) referrer-policy(no-referrer) ); background-image: url( "https://cdn.example.com/media@1.0.0/badge.svg" cross-origin(anonymous) referrer-policy(no-referrer) integrity("sha384-Iw/0p59dP96nGTzHvf2XIfqcBwBW7RM6JfOij8uZxyg5azfNaOOUW8SQy6H/hU91") ); }- Doğrulanmamış bir
JavaScript'te
CSS.supports()ile CSSurl()değiştirici desteğini özellik algılama:
export function getCssUrlModifierSupport() {
const supportsCrossOriginAndReferrer =
typeof CSS !== 'undefined' &&
typeof CSS.supports === 'function' &&
CSS.supports(
'background-image',
'url("https://example.com/a.svg" cross-origin(anonymous) referrer-policy(no-referrer))',
);
const supportsUrlIntegrity =
typeof CSS !== 'undefined' &&
typeof CSS.supports === 'function' &&
CSS.supports(
'background-image',
'url("https://example.com/a.svg" cross-origin(anonymous) referrer-policy(no-referrer) integrity("sha384-Iw/0p59dP96nGTzHvf2XIfqcBwBW7RM6JfOij8uZxyg5azfNaOOUW8SQy6H/hU91"))',
);
return { supportsCrossOriginAndReferrer, supportsUrlIntegrity };
}