Browser og frontend-sikkerhed

XSS og sikkerhedsheaders: beskyt webappen dér, hvor data bliver til en side

XSS opstår, når data, som skulle vises som tekst, får lov at blive fortolket som kode i en brugers browser. Sikker rendering er den vigtigste beskyttelse. En Content Security Policy og andre relevante HTTP-svarheaders kan begrænse skaden og afsløre usikre indlæsninger, men de kan ikke reparere en farlig kodevej alene.

Hvor kan XSS komme ind i en fungerende app?

Data bliver ikke pålidelige, fordi de allerede ligger i jeres database. Navne, kommentarer, importerede beskrivelser, filmetadata, URL-parametre og svar fra en integration kan stadig indeholde tegn eller markup, som browseren kan fortolke. Kortlæg derfor både kilden og det sted, hvor værdien bliver vist.

DataHvor vises den?Sikker standardSærlig risiko
Navn eller kommentarTekst i side eller tabelFrameworkets almindelige tekst-renderingRå HTML eller DOM-indsættelse
Formateret tekstBeskrivelse eller artikelSanitér med en vedligeholdt tilladelseslisteEvents, scripts og farlige URL-protokoller
Link fra import eller APIhref, billede eller omdirigeringTillad bevidste protokoller og destinationerjavascript:, data-URL eller åben omdirigering
JSON eller fejlsvarAPI-respons eller fejlvisningKorrekt content type og sikker tekstvisningSvar leveres som HTML eller indsættes råt

En gemt værdi kan ramme mange brugere og administrationen igen og igen. Derfor bør test også omfatte data, der bliver gemt, eksporteret, genindlæst og vist i en anden rolle end den, der oprettede dem.

Bevar frameworkets sikre tekst-rendering

Moderne frontend-frameworks hjælper normalt ved at kode særlige tegn, når værdier vises som almindelig tekst. Beskyttelsen forsvinder, hvis appen vælger en rå HTML-funktion, skriver direkte til innerHTML eller bygger script, CSS og URL'er ved at sætte ubetroede strenge sammen.

  • Vis tekst som tekst. Brug frameworkets normale binding eller DOM-egenskaber som textContent frem for rå HTML.
  • Find omvejene. Søg efter blandt andet innerHTML, outerHTML, document.write, rå HTML-funktioner og strenge, der bliver til kode.
  • Sanitér nødvendig formateret tekst. Hvis brugere reelt skal kunne skrive formateret HTML, så brug et vedligeholdt saniteringsbibliotek med en afgrænset tilladelsesliste og opdatér det løbende.
  • Ændr ikke efter sanitering. Senere strengmanipulation eller et bibliotek, der omskriver markup, kan gøre resultatet usikkert igen.
Inputvalidering er ikke nok. Et navn må gerne indeholde tegn, som også findes i HTML. Valider format og forretningsregler ved input, men gør værdien sikker i den kontekst, hvor den senere vises. Ellers risikerer I enten at blokere legitime data eller at acceptere en værdi, der er farlig i en anden kontekst.

Behandl links, filer og tredjepartsindhold som særskilte kontekster

Det samme tekststykke kræver forskellige regler alt efter, om det står i et afsnit, en HTML-attribut, en URL, CSS eller JavaScript. Undgå derfor en hjemmelavet “rens alt”-funktion. Brug den beskyttelse, der passer til den konkrete destination.

  • Begræns brugerleverede links til de URL-protokoller og destinationer, som funktionen faktisk kræver.
  • Brug den korrekte Content-Type på HTML, JSON, scripts, billeder og downloads; suppler med X-Content-Type-Options: nosniff.
  • Lad ikke en tredjeparts widget få mere adgang end nødvendigt. Hver ekstern scriptkilde bliver en del af appens browsermæssige tillidsgrænse.
  • Vis ikke serverfejl, stack traces eller ubetroede API-svar som HTML. Giv brugeren en stabil tekstbesked og gem tekniske detaljer i beskyttede logs.

Uploads har også egne regler for type, lagring og download. De er behandlet i den separate guide om sikker filupload og download.

Brug CSP som sikkerhedsnet – ikke som plaster

En Content Security Policy fortæller browseren, hvilke kilder der må levere scripts, styles, billeder, forbindelser og andet indhold. Den kan også begrænse formularers destinationer, blokere plugins og forhindre, at siden bliver indlejret til clickjacking. OWASP anbefaler CSP som et ekstra lag oven på sikker rendering, output encoding og sanitering – ikke som den eneste XSS-beskyttelse.

Illustrativ report-only-politik – skal tilpasses appens faktiske kilder

Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'

Eksemplet tillader kun egne scripts og forbindelser. Det vil derfor registrere brud for eksempelvis analyse, skrifter, betalingswidgets eller API'er på andre domæner. Tilføj kun en kilde, når I ved, hvilken funktion der kræver den. Undgå at “løse” rapporter med brede tilladelser som *, unsafe-inline eller unsafe-eval uden at forstå den tabte beskyttelse.

Rul politikken ud uden at gøre produktionen ubrugelig

  1. Kortlæg de nuværende kilder. Gennemgå HTML, netværkskald, tredjepartsscripts, styles, billeder, formularer, frames og forbindelser i de kritiske brugerrejser.
  2. Brug report-only. Content-Security-Policy-Report-Only håndhæver ikke politikken, men kan vise overtrædelser i browserens konsol og sende rapporter til et konfigureret endpoint.
  3. Sortér støj fra rigtige brud. Browserudvidelser og urelaterede kilder kan skabe rapporter. Bekræft problemet i et kontrolleret browserforløb før en tilladelse udvides.
  4. Håndhæv en afprøvet politik. Skift til Content-Security-Policy, når login, betaling, redigering, upload og andre kritiske forløb er testet i de relevante browsere.
  5. Overvåg efter ændringer. Nye widgets, analyseværktøjer og buildændringer kan kræve en bevidst opdatering; en bred permanent undtagelse bør ikke være standarden.

Nonces skal være uforudsigelige og forskellige for hvert HTTP-svar. De kræver derfor dynamisk HTML eller en platformfunktion, der kan indsætte værdien i både header og relevante script-tags. En statisk app kan i stedet bruge en politik, der passer til dens byggede filer, eller en dokumenteret hostingfunktion til dynamiske nonces.

Vælg headers efter appens funktion og hosting

Der findes ikke én headerblok, som passer til alle apps. En app, der skal kunne indlejres hos kunder, har for eksempel andre krav end et internt administrationssystem. Beslut formålet for hver header og kontrollér den faktiske live-respons.

Content-Security-Policy
Afgrænser indholdskilder og kan med frame-ancestors styre, hvem der må indlejre siden.
X-Content-Type-Options
nosniff beder browseren respektere den angivne MIME-type frem for at gætte.
Referrer-Policy
Styrer hvor meget af den aktuelle adresse der sendes videre, når browseren navigerer eller henter indhold.
Permissions-Policy
Begrænser browserfunktioner som kamera, mikrofon og geolocation, når appen ikke behøver dem.
Strict-Transport-Security
Kan tvinge fremtidige besøg over HTTPS. Kontrollér certifikater, underdomæner, hostingens egne standarder og en sikker tilbagevej, før lang levetid eller includeSubDomains vælges.

Netlify kan sætte headers via blandt andet _headers eller netlify.toml. Vercel bruger blandt andet vercel.json, Firebase Hosting firebase.json, og Azure Static Web Apps staticwebapp.config.json. Andre backends og reverse proxies har deres egne mekanismer. Følg dokumentationen til den platform og version, appen allerede bruger.

Test både kodevejen og det faktiske live-svar

En konfigurationsfil beviser ikke, at CDN, rewrite, funktion eller proxy leverer den forventede header. Test den udgivne adresse og alle relevante dokumenttyper.

  • Kontrollér HTTP-svarheaders på den faktiske appside, login, fejlside og andre svar, der gengiver HTML.
  • Kør de kritiske brugerrejser med report-only aktiv og gennemgå browserens CSP-rapporter og konsol.
  • Prøv gemt tekst med HTML-tegn, ugyldige URL-protokoller og formateret tekst, som saniteringen skal fjerne, i et isoleret testmiljø.
  • Bekræft at appen ikke kan indlejres, hvis frame-ancestors 'none' er den valgte regel, eller kun kan indlejres af de aftalte origins.
  • Gentag testen efter nye tredjepartsscripts, analyseværktøjer, editorer, uploads eller hostingændringer.
En enkel kontrol: curl -I https://jeres-app.example/ viser HTTP-svarheaders, men browserens DevTools er stadig nødvendig for at se, om politikken blokerer eller rapporterer noget under rigtig brug.

Typiske fejl

  • Alt HTML fjernes ved input: Legitime tegn går tabt, mens den samme værdi stadig kan være farlig i en URL- eller scriptkontekst.
  • Rå HTML vælges for at få formatering: Ubetroet markup bliver kode uden en vedligeholdt saniteringsregel.
  • CSP bliver eneste forsvar: Den usikre rendering består, og en bred undtagelse kan åbne angrebsvejen igen.
  • Politikken kopieres fra et andet site: Nødvendige funktioner bryder, eller unødvendige domæner får tillid.
  • Report-only bliver permanent: Overtrædelser registreres, men browseren blokerer dem aldrig.
  • Alle fejl løses med unsafe-inline: En central begrænsning mod inline script bliver sat ud af kraft.
  • Headeren findes kun lokalt: CDN eller hosting leverer et andet svar i produktion.
  • HSTS sættes aggressivt uden plan: Certifikat- eller underdomænefejl kan gøre legitime tjenester utilgængelige.

Tjekliste før medarbejdere eller kunder får adgang

  • ☐ Alle steder, hvor formular-, database-, URL-, fil- og integrationsdata vises i browseren, er kortlagt.
  • ☐ Almindelig tekst vises gennem frameworkets sikre standard eller en tilsvarende tekst-API.
  • ☐ Rå HTML-funktioner og usikre DOM-sinks er fjernet eller begrundet og beskyttet.
  • ☐ Nødvendig formateret tekst saniteres med en afgrænset, vedligeholdt løsning.
  • ☐ Links, omdirigeringer og ressource-URL'er accepterer kun de nødvendige protokoller og destinationer.
  • ☐ HTML, JSON, scripts, filer og fejl svarer med en bevidst og korrekt content type.
  • ☐ En CSP er tilpasset appens faktiske scripts, styles, billeder, forbindelser, formularer og frames.
  • ☐ CSP er afprøvet i report-only på de kritiske brugerrejser før håndhævelse.
  • ☐ Brede undtagelser som wildcard, unsafe-inline og unsafe-eval er fjernet eller dokumenteret med ejer og plan.
  • ☐ Clickjacking, MIME-sniffing, referrerdata og unødvendige browserfunktioner er vurderet.
  • ☐ HSTS er kun strammet efter kontrol af HTTPS, certifikater, underdomæner og hostingens standarder.
  • ☐ De forventede headers er bekræftet på den faktiske live-side og relevante fejlsvar.
  • ☐ Browserkonsol og CSP-rapporter overvåges efter nye widgets, editorer, analyse- og hostingændringer.

Officielle kilder

Frameworks, hostingplatforme og browserunderstøttelse ændrer sig. Kontrollér altid den officielle dokumentation til appens konkrete stack, før en politik håndhæves i produktion.

Når webappen virker, men browsergrænsen ikke er gennemgået

Hvis medarbejdere eller kunder snart skal bruge appen, kan Startklar hjælpe med at kortlægge usikre renderingsveje, tilpasse CSP og headers til den nuværende hosting og afprøve de kritiske forløb uden at låse løsningen til en bestemt teknologistak.

Se Startklar for AI-byggede apps