Härdning av HTTP-säkerhetshuvuden: En steg-för-steg-guide
Från underkänt till högsta betyg: implementera HSTS, nosniff, ram-skydd och Permissions-Policy omedelbart, rulla sedan ut Content-Security-Policy i tre säkra steg — med konfiguration för nginx och Apache.
Kör samma kontroll direkt – gratis
Ange din domän och få en 9-punkts audit – DNS, SPF/DKIM/DMARC, SSL, säkerhetsheaders, dark web-exponering – på 60 sekunder.
Ingen registrering · <60s · GDPR/EU-hantering
HTTP-säkerhetshuvuden är den billigaste säkerhetsåtgärden du någonsin kommer att implementera: ett antal svarshuvuden, inställda en gång på webbservern eller CDN:et, som instruerar varje besökande webbläsare att avvisa hela klasser av attacker — clickjacking, protokollnedgradering, MIME-sniffing, dataläckage mellan webbplatser och stora delar av cross-site scripting. Ändå saknar majoriteten av webbplatser dem fortfarande, eller använder värden kopierade från ett blogginlägg som tyst bryter funktionaliteten.
Denna guide vägleder en IT-ansvarig genom en komplett, stegvis härdning av en produktionswebbplats huvud: vad varje huvud gör, exakta värden att implementera, hur man rullar ut Content-Security-Policy utan att skada webbplatsen, webbserverkonfiguration för nginx och Apache, samt hur resultatet verifieras. Räkna med en arbetsdag fördelad över två till tre veckor (CSP report-only-perioden står för det mesta av arbetet).
Hur huvuden skyddar användare
Varje huvud i denna guide är en instruktion från din server till besökarens webbläsare. Webbläsaren verkställer det lokalt — ingen appliance, agent eller kodändring krävs:
Your server Visitor's browser
----------- -----------------
HTTP/1.1 200 OK
Strict-Transport-Security ------> "Never load this site over HTTP again"
Content-Security-Policy ------> "Only run scripts from these origins"
X-Frame-Options ------> "Refuse to render this site in an iframe"
X-Content-Type-Options ------> "Never guess file types"
Referrer-Policy ------> "Don't leak full URLs to other sites"
Permissions-Policy ------> "This site may not use camera/mic/location"
Eftersom verkställandet sker i webbläsaren skyddar huvuden dina användare även när attacken inte rör din server alls — till exempel en nätfiskesida som ramar in ditt inloggningsformulär, eller ett injicerat annonsskript som exfiltrerar formulärdata.
Steg 1 — Baslinje: mät innan du ändrar något
Kör din webbplats genom en skanner för säkerhetshuvuden — FortifyNets kostnadsfria security headers checker ger betyg för varje huvud och visar en enkel fix, och securityheaders.com är ett bra komplement. Spara resultatet. En typisk ohärdad webbplats får betyget F med endast Server och X-Powered-By närvarande — vilka båda läcker information snarare än att skydda något.
Inventera även vad webbplatsen faktiskt laddar. Öppna webbläsarens utvecklarverktyg (fliken Network) på dina fem viktigaste sidor och notera varje tredjepartsursprung: analysverktyg, typsnitt, tag-hanterare, chatt-widgets, betalnings-iframes, videoinbäddningar. Denna lista blir din CSP-allowlist i steg 4.
Steg 2 — Implementera de fem säkra huvudena omedelbart
Fem huvuden är i praktiken riskfria för nästan alla webbplatser och bör rullas ut i det första ändringsfönstret.
Strict-Transport-Security (HSTS)
Tvingar HTTPS för varje framtida besök, vilket motverkar SSL-stripping-attacker på publika Wi-Fi-nätverk.
Strict-Transport-Security: max-age=31536000; includeSubDomains
Börja med max-age=31536000 (ett år) endast om alla underdomäner redan kör HTTPS; annars börja med max-age=86400 utan includeSubDomains och expandera sedan. När det är stabilt, överväg HSTS preload — att vara hårdkodad i webbläsare tar bort även fönstret för det första besöket, men är i praktiken oåterkalleligt, så behandla preload som en envägsdörr.
X-Content-Type-Options
X-Content-Type-Options: nosniff
Hindrar webbläsare från att "sniffa" filtyper, vilket förhindrar att en användaruppladdad fil som serveras som text exekveras som skript. Det finns ingen legitim anledning att utelämna denna.
X-Frame-Options
X-Frame-Options: DENY
Blockerar clickjacking — en angripare som lägger sin egen inramade webbplats över din riktiga. Använd SAMEORIGIN istället om din egen webbplats legitimt ramar in sig själv (vissa adminpaneler och förhandsgranskningsfunktioner gör detta). Modern CSP frame-ancestors ersätter detta huvud, men behåll båda för äldre webbläsare.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
Säkerställer att länkar till externa webbplatser endast avslöjar ditt ursprung (https://example.com) istället för den fullständiga webbadressen — som kan innehålla söktermer, kontosökvägar eller återställningstokens. Detta värde är även modernt standard i webbläsare, men att ställa in det explicit garanterar det överallt.
Permissions-Policy
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Deklarerar vilka kraftfulla webbläsarfunktioner webbplatsen (och eventuella injicerade skript) får använda. Neka allt du inte använder; ett komprometterat tredjepartsskript kan då inte tyst begära åtkomst till kameran. Lägg tillbaka funktioner (t.ex. payment=(self "https://js.stripe.com")) endast där det genuint behövs.
Steg 3 — Ta bort huvuden som läcker information
När du redigerar konfigurationen, rensa bort onödiga standardvärden: Server-versionssträngar och X-Powered-By. De fyller ingen funktion och ger angripare dina exakta mjukvaruversioner för CVE-matchning. I nginx: server_tokens off;. I Apache: ServerTokens Prod och ServerSignature Off. För PHP: expose_php = Off.
Steg 4 — Content-Security-Policy, det stegvisa sättet
CSP är det mest kraftfulla huvudet — och det enda som kan bryta din webbplats om det implementeras slarvigt. Kopiera aldrig en CSP från en annan webbplats. Följ istället denna process i tre steg.
Steg A: Report-Only (1–2 veckor)
Distribuera policyn i Content-Security-Policy-Report-Only-läge. Webbläsare utvärderar den och rapporterar överträdelser, men blockerar ingenting:
Content-Security-Policy-Report-Only: default-src 'self';
script-src 'self' https://www.googletagmanager.com https://js.stripe.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https:;
frame-src https://js.stripe.com https://www.youtube-nocookie.com;
connect-src 'self' https://www.google-analytics.com;
frame-ancestors 'none';
report-uri /csp-report
Bygg din allowlist utifrån inventeringen i steg 1. Peka report-uri mot en enkel slutpunkt (eller en hostad tjänst) och låt den verkliga trafiken testa varje sida, inklusive kassan och sällan besökta kontosidor, i minst en vecka.
Steg B: Åtgärda överträdelserna
Granska rapporterna och konsolen i utvecklarverktygen. De vanliga fynden:
| Överträdelse | Orsak | Åtgärd |
|---|---|---|
| inline script blocked | onclick=-hanterare, inline script-taggar | flytta till externa filer, eller lägg till nonces per svar |
| eval blocked | gamla bibliotek, vissa tag-hanterare | uppgradera bibliotek; undvik 'unsafe-eval' |
| unknown origin | ett skript som laddar ett skript | lägg till ursprunget, eller ta bort widgeten |
| data: font | ikontypsnitt inbäddade i CSS | tillåt font-src data: eller byt till SVG-ikoner |
Guldstandarden för skript är nonces: servern genererar ett slumpmässigt värde per svar, lägger till det i huvudet (script-src 'nonce-R4nd0m') och i varje legitim skript-tagg. Injicerade skript saknar rätt nonce och stoppas. 'strict-dynamic' (CSP Level 3) låter sedan ett nonce-godkänt skript ladda sina egna beroenden — detta är Googles rekommenderade mönster och minskar din allowlist dramatiskt.
Acceptera 'unsafe-inline' för stilar om det innebär orimligt mycket arbete att ta bort det — den praktiska risken med inline CSS är betydligt lägre än inline JS. Acceptera inte 'unsafe-inline' för skript; det inaktiverar huvudets främsta värde.
Steg C: Verkställ
Byt namn på huvudet till Content-Security-Policy, håll rapportslutpunkten aktiv permanent, och bevaka de första 48 timmarna. Varje regression är bara en konfigurationsrad från en återställning till Report-Only.
Steg 5 — Webbserverkonfiguration
Ställ in huvuden på en central plats — webbservern eller CDN:et — inte per applikation, så att varje svar (inklusive felsidor och statiska tillgångar) täcks.
nginx (inuti server-blocket; always krävs för att huvuden även ska bifogas 4xx/5xx-svar):
server_tokens off;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; ..." always;
Se upp för den klassiska nginx-fällan: add_header-direktiv ärvs inte om ett location-block deklarerar egna add_header. Behåll dem alla på servernivå, eller upprepa hela uppsättningen.
Apache (i vhost eller .htaccess, med mod_headers aktiverat):
ServerTokens Prod
ServerSignature Off
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "DENY"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy "default-src 'self'; ..."
På CDN:er (Cloudflare, CloudFront, Vercel, Netlify), använd deras funktioner för svarshuvuden så att edge-servern applicerar samma uppsättning på cachade svar.
Steg 6 — Verifiera och fortsätt verifiera
Efter varje ändring: gör en hard-refresh med utvecklarverktygen öppna och läs de faktiska svarshuvudena; kör sedan headers checker och jämför med baslinjen från steg 1. En välhärdad webbplats når betyg A.
Inställningar kan förfalla. En redesign lägger till en widget som CSP blockerar; en migrering till en ny lastbalanserare råkar ta bort hela uppsättningen. Schemalägg verifieringen — FortifyNets kontinuerliga övervakning re-kontrollerar huvuden och larmar vid varje ändring, vilket är precis det "konfigurationsdrift"-fel som manuella processer missar.
Kak-härdning — de bortglömda svarshuvudena
Sessionskakor (cookies) sätts också via svarshuvuden, och en härdad huvud-uppsättning är ofullständig utan dem. Tre attribut på varje Set-Cookie:
``` Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax; Path=/ ```
- Secure — kakan skickas aldrig över okrypterad HTTP. Med HSTS på plats stänger detta loopen helt.
- HttpOnly — JavaScript kan inte läsa kakan, så även en lyckad XSS kan inte exfiltrera sessionstoken direkt.
- SameSite=Lax (eller Strict) — webbläsaren undanhåller kakan vid cross-site-förfrågningar, vilket neutraliserar de flesta CSRF-attacker till noll kodkostnad. Använd SameSite=None; Secure endast för kakor som genuint måste skickas mellan webbplatser (inbäddade widgets, SSO-flöden).
Överväg kaka-prefix för fördjupat försvar: en kaka namngiven __Host-session accepteras endast av webbläsare om den är Secure, saknar Domain-attribut och har Path=/ — vilket gör det omöjligt för en komprometterad underdomän att skriva över den.
Cross-origin isolation — COOP, CORP och CORS-sanity
Tre nyare huvuden kontrollerar hur din webbplats interagerar med andra ursprung på webbläsarnivå:
| Huvud | Rekommenderat värde | Vad det förhindrar |
|---|---|---|
| Cross-Origin-Opener-Policy | same-origin | andra webbplatser som håller en skriptbar referens till ditt fönster (tabnabbing, XS-Leaks) |
| Cross-Origin-Resource-Policy | same-origin (or same-site) | andra ursprung som bäddar in dina resurser (datastöld via inkludering) |
| Cross-Origin-Embedder-Policy | require-corp (advanced) | laddning av cross-origin-resurser som inte själva har godkänt det |
COOP: same-origin och CORP: same-origin är säkra för de flesta webbplatser och bör implementeras i samma ändring som steg 2. COEP är striktare — det bryter alla cross-origin-bilder eller skript som inte själva skickar CORP-huvuden — så implementera det endast om du behöver cross-origin-isolering (t.ex. för SharedArrayBuffer) och testa i Report-Only först (Cross-Origin-Embedder-Policy-Report-Only finns för just detta).
När du ändå håller på, sanity-checka CORS: Access-Control-Allow-Origin: * på ett API som använder kakor eller returnerar användardata är en verklig sårbarhet, inte en bekvämlighet. Tillåt specifika ursprung, och reflektera aldrig förfrågans Origin-huvud tillbaka utan validering.
Cachning av känsliga svar
Att härda huvuden inkluderar att se till att privat data inte lagras där du inte kan radera den. För alla autentiserade eller personliga svar:
``` Cache-Control: no-store ```
no-store överträffar de äldre Pragma- och Expires-kombinationerna och förhindrar både webbläsar- och mellanliggande cachning. Det klassiska felet: en utloggningsknapp som fungerar, men bakåtknappen visar fortfarande kontosidan från webbläsarens cache — no-store på autentiserade sidor löser det. Behåll långtids-cachning (Cache-Control: public, max-age=31536000, immutable) för statiska tillgångar med fingeravtryck; de två policys existerar sida vid sida per rutt.
Noteringar för SPA och ramverk
Single-page applications (SPA) ändrar CSP-kalkylen något:
- HTML-skalet serveras en gång, så nonces måste genereras per svar vid edge- eller servernivå — en statisk sajtgenerator som bakar in en nonce vid bygget har noll säkerhetsvärde. Om webbplatsen är helt statisk, använd hashvärden (sha256-…) av de specifika inline-skripten istället för nonces.
- Hydreringsramverk (Next.js, Nuxt) injicerar tillstånd som skripttaggar; båda stöder nonce-propagering från middleware — använd ramverkets dokumenterade CSP-integration istället för att kämpa mot den.
- connect-src är SPA:ns mest aktiva direktiv: varje API-ursprung, websocket-slutpunkt och telemetri-mål måste listas. Saknade poster misslyckas tyst för användare (förfrågningar blockeras, funktioner dör) — ännu en anledning till att Report-Only-steget är icke-förhandlingsbart.
- För API:er som konsumeras av webbläsare, applicera samma bashuvuden på API-svar: nosniff, no-store där det är relevant, och en restriktiv CSP (default-src 'none') på alla slutpunkter som någonsin kan öppnas direkt i en webbläsarflik.
Verifiering från kommandoraden
Skannrar är bekväma, men du bör också kunna verifiera huvuden direkt — särskilt vid felsökning av varför ett huvud finns på en rutt men saknas på en annan (nginx-fällan, en CDN-transform applicerad på endast ett sökvägsmönster, eller ett applikationsramverk som skriver över servern). Använd curl med flaggan för head-request (stort I), eller Network-panelen i webbläsarens utvecklarverktyg, och läs de råa svarshuvudena för tre URL:er: startsidan, en autentiserad rutt, och en sida som inte finns. Ett hälsosamt svar ser ut så här:
``` HTTP/2 200 content-security-policy: default-src 'self'; ... permissions-policy: camera=(), microphone=(), geolocation=() referrer-policy: strict-origin-when-cross-origin strict-transport-security: max-age=31536000; includeSubDomains x-content-type-options: nosniff x-frame-options: DENY ```
Kontrollera alla tre fall: startsidan, en autentiserad rutt och en 404. Upprepa kontrollen över både HTTP och HTTPS, samt på www- och root-domänvarianter om båda serveras — omdirigeringar kommer ofta från ett annat konfigurationsblock som inte bär med sig härdningen, och en SSL-stripping-attack börjar vid exakt det oskyddade första steget. Felsidan är den andra klassiska luckan — ramverk serverar ofta felmeddelanden genom en annan kodväg som hoppar över middleware, och en angripare som sonderar din webbplats ser mest felsidor. Om 404-sidan saknar huvuden som startsidan har, appliceras uppsättningen inte tillräckligt centralt; flytta den till server- eller edge-lagret.
Två vanor till som är värda att automatisera:
- CI-kontroll: ett skript på fem rader i deployment-pipelinen som kör curl mot staging-URL:en och avbryter bygget om ett förväntat huvud saknas. Detta fångar regressionen "ny lastbalanserare tog bort allt" innan den når produktion.
- Ändringsövervakning i produktion: extern övervakning som återläser huvuduppsättningen på schemalagd tid och larmar vid avvikelser — detta är en del av FortifyNets kontinuerliga övervakning, och det är så du får reda på regressioner som CI inte kunde se, såsom en ändring i CDN-konfigurationen gjord direkt i leverantörens dashboard.
Vanliga myter och misstag
- "Vi har en WAF, huvuden är redundanta." En WAF inspekterar trafik till din server; huvuden kontrollerar vad webbläsaren gör med dina sidor, inklusive attacker som aldrig rör din infrastruktur. De är komplementära lager.
- "X-XSS-Protection borde vara aktiverat." Nej — huvudet är utfasat; granskaren som flaggar för dess frånvaro är föråldrad. Moderna webbläsare har tagit bort XSS-revisorn som huvudet kontrollerade, och i gamla webbläsare introducerade det sårbarheter. Sätt det till 0 eller utelämna det helt; CSP är dess ersättare.
- "CSP bröt sajten en gång, så vi tog bort det." Felet var att hoppa över Report-Only, inte CSP i sig. Kör den stegvisa processen igen.
- "Betyg A betyder säker." Huvuden är ett lager. En A-betygsatt webbplats med ett opatchat CMS är fortfarande en plugin-CVE från att komprometteras — vilket är anledningen till att huvud-skanningen är ett test bland flera i en fullständig FortifyNet-revision.
Checklista för utrullning
- Baslinjeskanning sparad; inventering av tredjepartsursprung komplett
- HSTS, nosniff, X-Frame-Options, Referrer-Policy, Permissions-Policy implementerade
- Version-läckage via Server/X-Powered-By borttaget
- CSP körs i Report-Only med rapportslutpunkt
- Överträdelser triagerade; nonces används för skript; ingen 'unsafe-inline' för script-src
- CSP verkställt; frame-ancestors inställt; rapportering kvarstår
- Huvuden inställda centralt (server/CDN), always/Header always används
- Ny skanning visar betyg A; kontinuerlig övervakning aktiverad
Källor
Kontrollera din domän nu
Kör en gratis säkerhetsaudit och se om din domän har problemen som beskrivs i den här artikeln.