Jak działa ta kontrola
Scanaris przechodzi przez HTML Twojej strony głównej i przygląda się dwóm rodzajom znaczników: <script src="..."> i <link rel="stylesheet" href="...">. Rozwiązuje każdy adres względem adresu strony i uznaje go za zewnętrzny, jeśli jego źródło (schemat, domena i port) różni się od Twojego; obejmuje to adresy zaczynające się od //, które ładują z CDN z protokołem strony. Odrzuca data: i blob:. Dla każdego zasobu zewnętrznego sprawdza, czy ma atrybut integrity; jeśli brakuje, notuje go. Jeśli jest co najmniej jeden, otwiera ustalenie o niskiej wadze z liczbą zasobów i pierwszymi dziesięcioma adresami. Skrypty i style z Twojej własnej domeny nie są oznaczane: tam SRI nic nie wnosi.
Dlaczego to ważne
Gdy ładujesz bibliotekę z CDN, wykonujesz w przeglądarkach swoich użytkowników to, co ten CDN postanowi serwować. Jeśli CDN zostanie przejęty albo jego domena zmieni właściciela, plik może zostać podmieniony na inny, który robi to samo, a dodatkowo kradnie formularze albo przekierowuje do oszustw. Tak stało się w czerwcu 2024 roku z polyfill.io: domena została sprzedana, skrypt zaczął wstrzykiwać złośliwy kod i ponad sto tysięcy stron, które go dołączały, serwowało go, nie zauważając. Atrybut integrity zawiera hash pliku, który sprawdziłeś; przeglądarka liczy hash tego, co pobiera, i jeśli się nie zgadza, nie wykonuje go. To niska waga, bo najpierw CDN musi zostać zaatakowany, ale gdy to się stanie, szkoda jest całkowita i cicha.
Jak to naprawić
Opcja 1: dodać integrity do znaczników
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"
integrity="sha384-..." crossorigin="anonymous"></script>
Hash uzyskasz, pobierając dokładnie ten plik i uruchamiając:
curl -s https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js | openssl dgst -sha384 -binary | openssl base64 -A
cdnjs i jsDelivr pokazują gotowy do skopiowania hash obok każdego pliku. Atrybut crossorigin="anonymous" jest obowiązkowy, żeby przeglądarka mogła zweryfikować zasób z innego źródła. A adres musi wskazywać na stałą wersję (@4.4.0), nigdy na latest: jeśli CDN zaktualizuje plik, hash przestanie się zgadzać i Twoja strona przestanie ładować tę bibliotekę, czyli dokładnie to, czego chcesz przy niesprawdzonej zmianie.
Opcja 2: serwować biblioteki z własnej domeny
Zainstaluj je przez npm i pozwól bundlerowi (Vite, webpack, Nuxt, Next.js) włączyć je do builda. Wtedy plik wychodzi z Twojego serwera, z hashem w nazwie, a SRI przestaje być potrzebne. To zwykły wybór w nowoczesnych projektach i ten, który rozwiązuje ustalenie u źródła.
Co nie przyjmuje SRI
Arkusze stylów Google Fonts zmieniają się w zależności od przeglądarki, która o nie prosi, więc ich hash nie jest stabilny: albo akceptujesz to ustalenie, albo hostujesz fonty sam (co poprawia też prywatność i szybkość). Skrypty analityczne i reklamowe, które same się aktualizują (gtag.js, piksel Mety), też nie przyjmują stałego hasha; tam obroną jest CSP, która ogranicza, co może zrobić każde źródło, i którą mierzy słaba CSP.
Sprawdź, czy naprawione
curl -s https://twojadomena.pl | grep -oE '<(script|link)[^>]*(src|href)="(https?:)?//[^"]+"[^>]*>' | grep -v integrity
Każda linia, która się pojawi, to zasób zewnętrzny bez integrity. Jeśli zostają tylko te, które go nie przyjmują (fonty, analityka), skończyłeś.
Często zadawane pytania
Czy SRI spowalnia ładowanie?
Nie w zauważalny sposób: policzenie hasha SHA-384 pliku o kilkuset kilobajtach zajmuje milisekundy. To, co robi, to zmusza Cię do przypinania wersji, co i tak jest dobrą praktyką.
Jeśli zaktualizuję bibliotekę, muszę zmienić hash?
Tak, i o to chodzi: aktualizacja przechodzi przez Twoje ręce. Jeśli używasz npm i bundlera, proces jest taki jak zawsze, a hashem zajmuje się build.
A stare wersje bibliotek na CDN?
SRI gwarantuje, że plik jest tym, który wybrałeś, a nie że jest bezpieczny. jQuery 1.12 z poprawnym hashem nadal ma swoje luki; to wykrywa przestarzałe biblioteki.