{"id":156,"date":"2026-06-21T16:43:37","date_gmt":"2026-06-21T16:43:37","guid":{"rendered":"https:\/\/shattered.io\/se\/2026\/06\/21\/helmet-js-nodejs\/"},"modified":"2026-06-21T16:45:00","modified_gmt":"2026-06-21T16:45:00","slug":"helmet-js-nodejs","status":"publish","type":"post","link":"https:\/\/shattered.io\/se\/helmet-js-nodejs\/","title":{"rendered":"Helmet.js i Node.js: 12 Steg f\u00f6r HTTP-s\u00e4kerhetshuvuden [2026]"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>Helmet.js<\/strong> \u00e4r ett Express-middleware som automatiskt s\u00e4tter 13 HTTP-svarshuvuden och skyddar din Node.js-applikation mot XSS, clickjacking, MIME-sniffning och HTTPS-nedgradering. En enda rad kod, <code>app.use(helmet())<\/code>, aktiverar alla skydd p\u00e5 en g\u00e5ng. Den h\u00e4r guiden visar dig exakt hur du konfigurerar varje huvud, testar dem och drifts\u00e4tter dem i produktion p\u00e5 30 minuter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">HTTP-s\u00e4kerhetshuvuden \u00e4r instruktioner som servern skickar till webbl\u00e4saren och ber\u00e4ttar hur den ska hantera inneh\u00e5ll. Utan dem kan angripare injicera skadliga skript, lura anv\u00e4ndare att klicka p\u00e5 osynliga knappar och stj\u00e4la sessionsdata. Helmet.js version 8.2.0 l\u00f6ser detta med ett enda npm-paket som kr\u00e4ver Node.js 16 eller senare och fungerar med alla Express-baserade ramverk.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vad-ar-http-sakerhetshuvuden-och-varfor-de-spelar-roll\">Vad \u00e4r HTTP-s\u00e4kerhetshuvuden och varf\u00f6r de spelar roll<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">HTTP-s\u00e4kerhetshuvuden \u00e4r svarshuvuden som instruerar webbl\u00e4saren om hur den ska hantera en webbsidas inneh\u00e5ll. De fungerar som ett kontrakt: servern ber\u00e4ttar vad som \u00e4r till\u00e5tet och webbl\u00e4saren f\u00f6ljer dessa regler. Utan dem l\u00e4mnar du webbl\u00e4saren att gissa, och angripare utnyttjar just det utrymmet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Fyra av de vanligaste attackkategorierna motverkas direkt av s\u00e4kerhetshuvuden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Cross-Site Scripting (XSS)<\/strong>: angripare injicerar skadlig JavaScript i din sida. Content Security Policy begr\u00e4nsar vilka skriptk\u00e4llor webbl\u00e4saren accepterar.<\/li>\n<li><strong>Clickjacking<\/strong>: din sida b\u00e4ddas in i en osynlig iframe p\u00e5 en angriparsida. X-Frame-Options och CSP:s <code>frame-ancestors<\/code>-direktiv blockerar det.<\/li>\n<li><strong>MIME-sniffning<\/strong>: webbl\u00e4saren gissar filtyp och exekverar en uppladdad fil som skript. X-Content-Type-Options: nosniff f\u00f6rhindrar det.<\/li>\n<li><strong>HTTPS-nedgradering<\/strong>: angripare omdirigerar trafik till HTTP via man-in-the-middle. Strict-Transport-Security tvingar webbl\u00e4saren att alltid anv\u00e4nda HTTPS.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet.js s\u00e4tter 13 huvuden i ett enda anrop. Utan Helmet skulle du beh\u00f6va s\u00e4tta varje huvud manuellt i varje route-handler, vilket leder till inkonsekvent konfiguration och gl\u00f6mda skydd i nya endpoints.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">OWASP:s projekt Secure Headers Project listar exakt vilka huvuden moderna webbapplikationer b\u00f6r s\u00e4tta, och Helmet.js t\u00e4cker samtliga i deras rekommenderade lista. Det \u00e4r d\u00e4rf\u00f6r Helmet.js \u00e4r branschstandard f\u00f6r Node.js-applikationer i produktion. Du kan se hela OWASP-rekommendationen p\u00e5 <a href=\"https:\/\/owasp.org\/www-project-secure-headers\/\" target=\"_blank\" rel=\"noopener noreferrer\">owasp.org\/www-project-secure-headers<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"de-13-huvuden-helmet-js-satter-som-standard\">De 13 huvuden Helmet.js s\u00e4tter som standard<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet.js version 8.2.0 aktiverar 13 HTTP-svarshuvuden i standardkonfigurationen. Tabellen nedan visar varje huvud, dess standardv\u00e4rde och vad det skyddar mot.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Huvud<\/th><th>Standardv\u00e4rde<\/th><th>Skyddar mot<\/th><\/tr><\/thead><tbody><tr><td>Content-Security-Policy<\/td><td>default-src &#8216;self&#8217;; script-src &#8216;self&#8217;; object-src &#8216;none&#8217;<\/td><td>XSS, skriptinjektion<\/td><\/tr><tr><td>Cross-Origin-Opener-Policy<\/td><td>same-origin<\/td><td>Cross-origin f\u00f6nster\u00e5tkomst<\/td><\/tr><tr><td>Cross-Origin-Resource-Policy<\/td><td>same-origin<\/td><td>Cross-origin resursl\u00e4sning<\/td><\/tr><tr><td>Origin-Agent-Cluster<\/td><td>?1<\/td><td>Processisolering<\/td><\/tr><tr><td>Referrer-Policy<\/td><td>no-referrer<\/td><td>URL-informationsl\u00e4ckage<\/td><\/tr><tr><td>Strict-Transport-Security<\/td><td>max-age=15552000; includeSubDomains<\/td><td>HTTPS-nedgradering<\/td><\/tr><tr><td>X-Content-Type-Options<\/td><td>nosniff<\/td><td>MIME-sniffning<\/td><\/tr><tr><td>X-DNS-Prefetch-Control<\/td><td>off<\/td><td>DNS-f\u00f6rl\u00e4sning<\/td><\/tr><tr><td>X-Download-Options<\/td><td>noopen<\/td><td>IE-fil\u00f6ppning<\/td><\/tr><tr><td>X-Frame-Options<\/td><td>SAMEORIGIN<\/td><td>Clickjacking<\/td><\/tr><tr><td>X-Permitted-Cross-Domain-Policies<\/td><td>none<\/td><td>Adobe Flash-policyer<\/td><\/tr><tr><td>X-Powered-By<\/td><td>Borttagen<\/td><td>Serverinformationsl\u00e4ckage<\/td><\/tr><tr><td>X-XSS-Protection<\/td><td>Inaktiverad (0)<\/td><td>\u00c4ldre os\u00e4ker XSS-filter<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Standardkonfigurationen \u00e4r s\u00e4ker och fungerar f\u00f6r de flesta appar. Du beh\u00f6ver bara anpassa CSP och HSTS f\u00f6r ditt specifika fall, vilket stegen l\u00e4ngre ner i guiden visar.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"forutsattningar\">F\u00f6ruts\u00e4ttningar<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Innan du b\u00f6rjar, kontrollera att du har f\u00f6ljande installerat:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Node.js 16 eller senare<\/strong> (Helmet 8.x kr\u00e4ver Node 16+). K\u00f6r <code>node --version<\/code> f\u00f6r att kontrollera.<\/li>\n<li><strong>npm 8 eller senare<\/strong>. K\u00f6r <code>npm --version<\/code>.<\/li>\n<li><strong>Express.js<\/strong> (fungerar med Express 4.x och 5.x)<\/li>\n<li>Grundl\u00e4ggande kunskaper om Express-middleware<\/li>\n<li>En textredigerare och terminal<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Guiden anv\u00e4nder ES-moduler (import\/export) med <code>\"type\": \"module\"<\/code> i package.json. Om du anv\u00e4nder CommonJS (<code>require()<\/code>) fungerar Helmet.js precis lika bra, men syntaxen skiljer sig n\u00e5got.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-1-skapa-node-js-projektet\">Steg 1: Skapa Node.js-projektet<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">B\u00f6rja med att skapa en ny projektkatalog och initiera ett npm-projekt. Den h\u00e4r strukturen h\u00e5ller konfigurationsfilerna organiserade och g\u00f6r det enkelt att l\u00e4gga till fler moduler senare.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir helmet-demo && cd helmet-demo\nnpm init -y\nnpm pkg set type=\"module\"\nnpm pkg set engines.node=\">=16.0.0\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Skapa katalogstrukturen f\u00f6r projektet:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>helmet-demo\/\n\u251c\u2500\u2500 src\/\n\u2502   \u251c\u2500\u2500 app.js          # Express-appkonfiguration\n\u2502   \u251c\u2500\u2500 routes\/\n\u2502   \u2502   \u2514\u2500\u2500 api.js      # API-routes\n\u2502   \u2514\u2500\u2500 middleware\/\n\u2502       \u2514\u2500\u2500 security.js # Helmet-konfiguration\n\u251c\u2500\u2500 public\/\n\u2502   \u2514\u2500\u2500 index.html      # Testsida\n\u251c\u2500\u2500 .env\n\u2514\u2500\u2500 package.json<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet.js kr\u00e4ver ingen databas eller extern tj\u00e4nst, s\u00e5 projektet kan k\u00f6ras lokalt direkt efter installationen i steg 2.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-2-installera-helmet-js-8-2-0\">Steg 2: Installera Helmet.js 8.2.0<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Installera Helmet.js och Express med npm. Du beh\u00f6ver ocks\u00e5 dotenv f\u00f6r milj\u00f6variabler och ett testverktyg f\u00f6r att verifiera svarsrubrikerna.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm install helmet express dotenv\nnpm install --save-dev nodemon<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Kontrollera att du har r\u00e4tt version:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm list helmet\n# F\u00f6rv\u00e4ntat utdata:\n# helmet-demo@1.0.0\n# \u2514\u2500\u2500 helmet@8.2.0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">L\u00e4gg till start-skript i package.json:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"name\": \"helmet-demo\",\n  \"version\": \"1.0.0\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"start\": \"node src\/app.js\",\n    \"dev\": \"nodemon src\/app.js\"\n  },\n  \"engines\": {\n    \"node\": \">=16.0.0\"\n  }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-3-grundkonfiguration-med-express\">Steg 3: Grundkonfiguration med Express<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Skapa <code>src\/app.js<\/code> med den grundl\u00e4ggande Express- och Helmet-konfigurationen. Nyckelregeln \u00e4r att anropa <code>app.use(helmet())<\/code> <strong>tidigt i middleware-kedjan<\/strong>, innan dina routes definieras. Om du s\u00e4tter Helmet efter dina routes kan f\u00f6rfr\u00e5gningar passera utan s\u00e4kerhetshuvuden.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import express from 'express';\nimport helmet from 'helmet';\nimport { fileURLToPath } from 'url';\nimport path from 'path';\nimport 'dotenv\/config';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\nconst app = express();\nconst PORT = process.env.PORT || 3000;\n\n\/\/ Helmet M\u00c5STE anropas f\u00f6re alla routes\napp.use(helmet());\n\n\/\/ JSON-parser\napp.use(express.json());\napp.use(express.urlencoded({ extended: true }));\n\n\/\/ Statiska filer\napp.use(express.static(path.join(__dirname, '..', 'public')));\n\n\/\/ H\u00e4lsokontroll\napp.get('\/health', (req, res) => {\n  res.json({ status: 'OK', timestamp: new Date().toISOString() });\n});\n\napp.listen(PORT, () => {\n  console.log(`Server k\u00f6r p\u00e5 port ${PORT}`);\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Starta servern och kontrollera att alla 13 huvuden s\u00e4tts:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm run dev\n\n# Testa med curl i en annan terminal:\ncurl -I http:\/\/localhost:3000\/health<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00f6rv\u00e4ntat utdata fr\u00e5n curl-kommandot:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>HTTP\/1.1 200 OK\nContent-Security-Policy: default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests\nCross-Origin-Opener-Policy: same-origin\nCross-Origin-Resource-Policy: same-origin\nOrigin-Agent-Cluster: ?1\nReferrer-Policy: no-referrer\nStrict-Transport-Security: max-age=15552000; includeSubDomains\nX-Content-Type-Options: nosniff\nX-DNS-Prefetch-Control: off\nX-Download-Options: noopen\nX-Frame-Options: SAMEORIGIN\nX-Permitted-Cross-Domain-Policies: none<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Observera att X-Powered-By saknas i svaret. Det \u00e4r ett avsiktligt borttagande. Utan Helmet avsl\u00f6jar Express automatiskt <code>X-Powered-By: Express<\/code>, vilket ber\u00e4ttar f\u00f6r angripare exakt vilken teknologi din server k\u00f6r och underl\u00e4ttar riktade attacker. Helmet tar bort det huvud helt och h\u00e5llet.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-4-anpassa-content-security-policy\">Steg 4: Anpassa Content Security Policy<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Content Security Policy (CSP) \u00e4r det kraftfullaste HTTP-s\u00e4kerhetshuvudet och skyddar mot XSS-attacker genom att begr\u00e4nsa vilka resurser webbl\u00e4saren f\u00e5r ladda. Helmets standardkonfiguration \u00e4r mycket restriktiv och blockerar allt som inte kommer fr\u00e5n din egen server.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">De vanligaste CSP-direktiven och deras funktion:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Direktiv<\/th><th>Standardv\u00e4rde<\/th><th>Beskrivning<\/th><\/tr><\/thead><tbody><tr><td>default-src<\/td><td>&#8216;self&#8217;<\/td><td>Fallback f\u00f6r alla resurstyper<\/td><\/tr><tr><td>script-src<\/td><td>&#8216;self&#8217;<\/td><td>JavaScript-k\u00e4llkoder<\/td><\/tr><tr><td>style-src<\/td><td>&#8216;self&#8217; https: &#8216;unsafe-inline&#8217;<\/td><td>CSS-k\u00e4llor (inkl. inline)<\/td><\/tr><tr><td>img-src<\/td><td>&#8216;self&#8217; data:<\/td><td>Bildk\u00e4llor<\/td><\/tr><tr><td>font-src<\/td><td>&#8216;self&#8217; https: data:<\/td><td>Typsnittsk\u00e4llor<\/td><\/tr><tr><td>object-src<\/td><td>&#8216;none&#8217;<\/td><td>Blockerar plugins (Flash etc.)<\/td><\/tr><tr><td>frame-ancestors<\/td><td>&#8216;self&#8217;<\/td><td>Vem som f\u00e5r b\u00e4dda in sidan<\/td><\/tr><tr><td>base-uri<\/td><td>&#8216;self&#8217;<\/td><td>Begr\u00e4nsar base-taggens URI<\/td><\/tr><tr><td>form-action<\/td><td>&#8216;self&#8217;<\/td><td>Formul\u00e4rs\u00e4ndningsm\u00e5l<\/td><\/tr><tr><td>upgrade-insecure-requests<\/td><td>Aktiverat<\/td><td>Uppgraderar HTTP till HTTPS<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Om din app laddar resurser fr\u00e5n CDN, Google Fonts eller tredjepartstj\u00e4nster beh\u00f6ver du ut\u00f6ka standardkonfigurationen. Skapa <code>src\/middleware\/security.js<\/code> med anpassad CSP:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import helmet from 'helmet';\n\nconst NODE_ENV = process.env.NODE_ENV || 'development';\nconst isDev = NODE_ENV === 'development';\n\nexport const helmetConfig = helmet({\n  contentSecurityPolicy: {\n    useDefaults: true,\n    directives: {\n      \/\/ Till\u00e5t skript fr\u00e5n din server och CDN\n      scriptSrc: [\n        \"'self'\",\n        \"https:\/\/cdn.jsdelivr.net\",\n        isDev ? \"'unsafe-eval'\" : null,\n      ].filter(Boolean),\n\n      \/\/ Till\u00e5t stilar fr\u00e5n Google Fonts\n      styleSrc: [\n        \"'self'\",\n        \"https:\/\/fonts.googleapis.com\",\n        \"'unsafe-inline'\", \/\/ Beh\u00f6vs f\u00f6r m\u00e5nga CSS-ramverk\n      ],\n\n      \/\/ Till\u00e5t typsnitt fr\u00e5n Google Fonts\n      fontSrc: [\n        \"'self'\",\n        \"https:\/\/fonts.gstatic.com\",\n        \"data:\",\n      ],\n\n      \/\/ Till\u00e5t bilder fr\u00e5n din server och data-URIer\n      imgSrc: [\"'self'\", \"data:\", \"https:\"],\n\n      \/\/ Till\u00e5t API-anrop till din egen backend\n      connectSrc: [\"'self'\", \"https:\/\/api.dinapp.se\"],\n\n      \/\/ Blockera alltid plugins\n      objectSrc: [\"'none'\"],\n\n      \/\/ Uppgradera ins\u00e4kra f\u00f6rfr\u00e5gningar (HTTP \u2192 HTTPS)\n      upgradeInsecureRequests: isDev ? [] : null,\n    },\n  },\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Importera sedan den anpassade konfigurationen i app.js:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { helmetConfig } from '.\/middleware\/security.js';\n\n\/\/ Ers\u00e4tt app.use(helmet()) med:\napp.use(helmetConfig);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">CSP kan verifieras med Mozillas CSP Evaluator, som pekar ut svaga direktiv och potentiella kringg\u00e5enden. L\u00e4nk till <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Content-Security-Policy\" target=\"_blank\" rel=\"noopener noreferrer\">MDN:s dokumentation om Content-Security-Policy<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-5-strict-transport-security-hsts-for-https\">Steg 5: Strict-Transport-Security (HSTS) f\u00f6r HTTPS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Strict-Transport-Security (HSTS) ber\u00e4ttar f\u00f6r webbl\u00e4saren att alltid anv\u00e4nda HTTPS f\u00f6r din dom\u00e4n, \u00e4ven om anv\u00e4ndaren skriver <code>http:\/\/<\/code>. Helmets standardv\u00e4rde \u00e4r <code>max-age=15552000; includeSubDomains<\/code>, vilket motsvarar 180 dagar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00f6r produktion b\u00f6r du h\u00f6ja max-age till 1 \u00e5r (31536000 sekunder) och l\u00e4gga till preload-direktivet om du vill registrera din dom\u00e4n i webbl\u00e4sarnas inbyggda HSTS-listor. HSTS-preload inneb\u00e4r att webbl\u00e4sare vet att anv\u00e4nda HTTPS f\u00f6r din dom\u00e4n redan innan den f\u00f6rsta HTTP-f\u00f6rfr\u00e5gan, vilket eliminerar den initiala os\u00e4kra anslutningen helt och h\u00e5llet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Krav f\u00f6r att registreras i HSTS Preload List:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>max-age p\u00e5 minst 31536000 sekunder (1 \u00e5r)<\/li>\n<li>Direktivet <code>includeSubDomains<\/code> m\u00e5ste vara inkluderat<\/li>\n<li>Direktivet <code>preload<\/code> m\u00e5ste finnas i headern<\/li>\n<li>Alla subdom\u00e4ner m\u00e5ste st\u00f6dja HTTPS<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>export const helmetConfig = helmet({\n  \/\/ HSTS-konfiguration f\u00f6r produktion\n  strictTransportSecurity: {\n    maxAge: 31536000,        \/\/ 1 \u00e5r (31 536 000 sekunder)\n    includeSubDomains: true, \/\/ G\u00e4ller alla subdom\u00e4ner\n    preload: true,           \/\/ Registreras i HSTS Preload List\n  },\n\n  \/\/ \u00d6vrig konfiguration...\n  contentSecurityPolicy: { \/* ... *\/ },\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Viktigt<\/strong>: Aktivera aldrig HSTS-preload p\u00e5 en dom\u00e4n d\u00e4r alla subdom\u00e4ner inte st\u00f6der HTTPS. Om en subdom\u00e4n saknar TLS-certifikat kommer anv\u00e4ndare dit att se ett certifikatfel som inte kan kringg\u00e5s, eftersom webbl\u00e4saren v\u00e4grar HTTP-anslutningen. L\u00e4s mer om HSTS p\u00e5 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Strict-Transport-Security\" target=\"_blank\" rel=\"noopener noreferrer\">MDN:s HSTS-dokumentation<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Under lokal utveckling, inaktivera HSTS f\u00f6r att undvika problem:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export const helmetConfig = helmet({\n  strictTransportSecurity: isDev ? false : {\n    maxAge: 31536000,\n    includeSubDomains: true,\n    preload: true,\n  },\n});<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-6-x-frame-options-mot-clickjacking\">Steg 6: X-Frame-Options mot clickjacking<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Clickjacking \u00e4r en attack d\u00e4r din sida b\u00e4ddas in i en osynlig iframe p\u00e5 en angriparsida. Angriparen l\u00e4gger sedan en genomskinlig overlay ovanp\u00e5 sin sida och lurar anv\u00e4ndare att klicka p\u00e5 knappar de inte ser, till exempel &#8220;Skicka betalning&#8221; eller &#8220;Godk\u00e4nn beh\u00f6righet&#8221;.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet s\u00e4tter <code>X-Frame-Options: SAMEORIGIN<\/code> som standard, vilket till\u00e5ter att sidan b\u00e4ddas in i iframe:ar p\u00e5 samma dom\u00e4n men blockerar det p\u00e5 andra dom\u00e4ner. Tre m\u00f6jliga v\u00e4rden:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>DENY<\/strong>: Blockerar all inb\u00e4ddning i iframe:ar, \u00e4ven p\u00e5 samma dom\u00e4n.<\/li>\n<li><strong>SAMEORIGIN<\/strong>: Till\u00e5ter inb\u00e4ddning fr\u00e5n samma dom\u00e4n (Helmets standard).<\/li>\n<li><strong>ALLOW-FROM uri<\/strong>: Till\u00e5ter inb\u00e4ddning fr\u00e5n specifik URI (d\u00e5ligt st\u00f6d i moderna webbl\u00e4sare).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Om din app aldrig beh\u00f6ver b\u00e4ddas in i en iframe (vilket g\u00e4ller de flesta backend-API:er och admin-paneler), s\u00e4tt DENY:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export const helmetConfig = helmet({\n  frameguard: {\n    action: 'deny', \/\/ Blockerar ALL iframe-inb\u00e4ddning\n  },\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Modern CSP med <code>frame-ancestors<\/code>-direktivet ger mer flexibel kontroll och \u00e4r det f\u00f6redragna alternativet i nya appar. Helmets standard-CSP inneh\u00e5ller redan <code>frame-ancestors 'self'<\/code>, vilket ger samma skydd som <code>SAMEORIGIN<\/code>. Du kan lita p\u00e5 att standardkonfigurationen skyddar dig mot clickjacking utan ytterligare konfiguration.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-7-x-content-type-options-mot-mime-sniffning\">Steg 7: X-Content-Type-Options mot MIME-sniffning<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">MIME-sniffning intr\u00e4ffar n\u00e4r webbl\u00e4saren ignorerar den Content-Type-header som servern skickar och ist\u00e4llet gissar filtypen baserat p\u00e5 inneh\u00e5llet. En angripare som laddar upp en fil med till\u00e4gget <code>.jpg<\/code> men med JavaScript-inneh\u00e5ll kan f\u00e5 webbl\u00e4saren att exekvera den som ett skript, trots att servern skickade <code>Content-Type: image\/jpeg<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet s\u00e4tter <code>X-Content-Type-Options: nosniff<\/code> som standard. Det \u00e4r ett enkelt huvud med ett enda giltigt v\u00e4rde, <code>nosniff<\/code>, och det beh\u00f6ver s\u00e4llan konfigureras manuellt. Helmets standardinst\u00e4llning \u00e4r korrekt och beh\u00f6ver inte \u00e4ndras.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">En f\u00f6ruts\u00e4ttning \u00e4r att din server s\u00e4tter korrekta <code>Content-Type<\/code>-headers f\u00f6r alla resurser. Om din server s\u00e4nder fel Content-Type och du har <code>nosniff<\/code> aktiverat kan CSS- och JavaScript-filer v\u00e4gras av webbl\u00e4saren. Det \u00e4r ett konfigurationsfel p\u00e5 serversidan, inte ett fel i Helmet.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Verifiera att headern finns i svaret:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -I http:\/\/localhost:3000\/health | grep X-Content-Type\n# F\u00f6rv\u00e4ntat utdata:\n# X-Content-Type-Options: nosniff<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Mer teknisk bakgrund finns p\u00e5 <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/X-Content-Type-Options\" target=\"_blank\" rel=\"noopener noreferrer\">MDN:s dokumentation om X-Content-Type-Options<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-8-referrer-policy-for-informationsskydd\">Steg 8: Referrer-Policy f\u00f6r informationsskydd<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00e4r en anv\u00e4ndare klickar p\u00e5 en l\u00e4nk skickar webbl\u00e4saren en Referer-header till destinationssidan som avsl\u00f6jar vilken URL anv\u00e4ndaren kom fr\u00e5n. Om din URL inneh\u00e5ller k\u00e4nslig information, som ett sessionstoken i query-str\u00e4ngen (<code>\/reset-password?token=abc123<\/code>), kan det l\u00e4cka till tredjepartstj\u00e4nster via Referer-headern.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet s\u00e4tter <code>Referrer-Policy: no-referrer<\/code> som standard, vilket inneb\u00e4r att inga Referer-data skickas till externa sidor. Det \u00e4r det mest restriktiva alternativet och det s\u00e4kraste valet f\u00f6r de flesta applikationer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Om din app beh\u00f6ver webbplatsanalys eller att externa tj\u00e4nster k\u00e4nner till ursprungssidan, anv\u00e4nd ett av de mer till\u00e5tande alternativen:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Policy<\/th><th>Skickar Referer till<\/th><th>Inneh\u00e5ller URL-s\u00f6kv\u00e4g<\/th><\/tr><\/thead><tbody><tr><td>no-referrer<\/td><td>Ingen<\/td><td>Nej<\/td><\/tr><tr><td>same-origin<\/td><td>Samma dom\u00e4n<\/td><td>Ja<\/td><\/tr><tr><td>strict-origin<\/td><td>Alla (HTTPS-ursprung)<\/td><td>Nej<\/td><\/tr><tr><td>strict-origin-when-cross-origin<\/td><td>Alla (HTTPS-ursprung)<\/td><td>Ja (samma origin)<\/td><\/tr><tr><td>no-referrer-when-downgrade<\/td><td>HTTPS till HTTPS<\/td><td>Ja<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00f6r appar med Google Analytics eller liknande verktyg \u00e4r <code>strict-origin-when-cross-origin<\/code> ett bra kompromissalternativ som delar ursprungsdom\u00e4nen men inte URL-s\u00f6kv\u00e4gen med externa sidor:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export const helmetConfig = helmet({\n  referrerPolicy: {\n    policy: 'strict-origin-when-cross-origin',\n  },\n});<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-9-permissions-policy-for-webblasarfunktioner\">Steg 9: Permissions-Policy f\u00f6r webbl\u00e4sarfunktioner<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Permissions-Policy (tidigare Feature-Policy) kontrollerar vilka webbl\u00e4sarfunktioner din sida och inb\u00e4ddade iframes f\u00e5r anv\u00e4nda. Det handlar om funktioner som kamera, mikrofon, geolokalisering, betalnings-API:er och fullsk\u00e4rmsl\u00e4ge. Utan en policy kan tredjepartsskript som laddas p\u00e5 din sida beg\u00e4ra kameratillg\u00e5ng utan din vetskap.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet inkluderar Permissions-Policy i sin standardkonfiguration. F\u00f6r att anpassa vilka funktioner som till\u00e5ts, l\u00e4gg till <code>permissionsPolicy<\/code>-konfigurationen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export const helmetConfig = helmet({\n  permissionsPolicy: {\n    features: {\n      \/\/ Till\u00e5t geolokalisering f\u00f6r din app\n      geolocation: ['self'],\n\n      \/\/ Blockera kamera och mikrofon (om de inte beh\u00f6vs)\n      camera: [],\n      microphone: [],\n\n      \/\/ Till\u00e5t fullsk\u00e4rm fr\u00e5n din dom\u00e4n\n      fullscreen: ['self'],\n\n      \/\/ Blockera betalnings-API:er fr\u00e5n tredjeparter\n      payment: ['self'],\n\n      \/\/ Inaktivera USB-\u00e5tkomst\n      usb: [],\n\n      \/\/ Inaktivera Motion-sensorer\n      accelerometer: [],\n      gyroscope: [],\n    },\n  },\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Tomma arrayer (<code>[]<\/code>) blockerar funktionen helt, inklusive f\u00f6r inb\u00e4ddade iframes. <code>['self']<\/code> till\u00e5ter funktionen f\u00f6r din sida men inte f\u00f6r iframes som laddas fr\u00e5n externa dom\u00e4ner.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-10-cross-origin-isolation-for-processisolering\">Steg 10: Cross-Origin-isolation f\u00f6r processisolering<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Tre Cross-Origin-relaterade huvuden f\u00f6rst\u00e4rker webbl\u00e4sarens processisolering och minskar risken f\u00f6r sidokanal-attacker som Spectre och Meltdown, vilka kan l\u00e4sa data ur andra tabbars minnesomr\u00e5de.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet s\u00e4tter alla tre som standard:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Cross-Origin-Opener-Policy: same-origin<\/strong>: Isolerar din sida i sin egen webbl\u00e4sarprocess, vilket f\u00f6rhindrar att andra sidor kan komma \u00e5t ditt f\u00f6nsterobjekt via <code>window.open()<\/code>.<\/li>\n<li><strong>Cross-Origin-Resource-Policy: same-origin<\/strong>: F\u00f6rhindrar att externa sidor inkluderar dina resurser (bilder, skript, data) via <code>&lt;img&gt;<\/code>&#8211; eller <code>&lt;script&gt;<\/code>-taggar.<\/li>\n<li><strong>Origin-Agent-Cluster: ?1<\/strong>: Beg\u00e4r att webbl\u00e4saren placerar din sida i ett eget agentnoder, vilket ger starkare minnesisoleringen.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Om din app tillhandah\u00e5ller resurser som ska kunna b\u00e4ddas in av externa sidor (till exempel bilder i en CDN eller widgets), beh\u00f6ver du \u00e4ndra Cross-Origin-Resource-Policy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export const helmetConfig = helmet({\n  \/\/ Till\u00e5t cross-origin resursinkludering (f\u00f6r publika CDN-resurser)\n  crossOriginResourcePolicy: {\n    policy: 'cross-origin',\n  },\n\n  \/\/ Beh\u00e5ll opener-isolering\n  crossOriginOpenerPolicy: {\n    policy: 'same-origin',\n  },\n});<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-11-csp-med-nonces-for-inline-skript\">Steg 11: CSP med nonces f\u00f6r inline-skript<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Helmets standard-CSP blockerar alla inline-skript (<code>&lt;script&gt;...&lt;\/script&gt;<\/code>) och inline-stilar utan k\u00e4llangivelse. Det \u00e4r det korrekta beteendet ur s\u00e4kerhetssynpunkt, men det bryter \u00e4ldre applikationer som anv\u00e4nder inline-skript flitigt.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">L\u00f6sningen \u00e4r nonces: en eng\u00e5ngskod som genereras f\u00f6r varje f\u00f6rfr\u00e5gan och bifogas b\u00e5de i CSP-headern och i inline-skripttaggarna. Webbl\u00e4saren accepterar bara inline-skript med matchande nonce, vilket omintetg\u00f6r XSS-attacker utan att kr\u00e4va att du konverterar alla inline-skript till externa filer.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import crypto from 'crypto';\nimport helmet from 'helmet';\n\nexport function createHelmetWithNonce() {\n  return [\n    \/\/ Middleware 1: Generera nonce per f\u00f6rfr\u00e5gan\n    (req, res, next) => {\n      res.locals.cspNonce = crypto.randomBytes(16).toString('base64');\n      next();\n    },\n\n    \/\/ Middleware 2: Konfigurera Helmet med nonce-funktion\n    helmet({\n      contentSecurityPolicy: {\n        useDefaults: true,\n        directives: {\n          scriptSrc: [\n            \"'self'\",\n            \/\/ Funktionen anropas per f\u00f6rfr\u00e5gan och returnerar nonce-v\u00e4rdet\n            (req, res) => `'nonce-${res.locals.cspNonce}'`,\n          ],\n          \/\/ Inaktivera unsafe-inline om det var aktiverat\n          styleSrc: [\"'self'\", \"https:\"],\n        },\n      },\n    }),\n  ];\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Uppdatera app.js f\u00f6r att anv\u00e4nda nonce-factory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { createHelmetWithNonce } from '.\/middleware\/security.js';\n\n\/\/ Spread array-av-middleware\napp.use(...createHelmetWithNonce());\n\n\/\/ I din template-motor, anv\u00e4nd nonce:\napp.get('\/', (req, res) => {\n  res.send(`\n    <!DOCTYPE html>\n    <html>\n      <head>\n        <title>Demo<\/title>\n      <\/head>\n      <body>\n        <!-- Nonce-skyddat inline-skript -->\n        <script nonce=\"${res.locals.cspNonce}\">\n          console.log('Skyddat inline-skript');\n        <\/script>\n      <\/body>\n    <\/html>\n  `);\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Nonce-v\u00e4rdet \u00e4ndras vid varje f\u00f6rfr\u00e5gan, vilket g\u00f6r att en angripare inte kan f\u00f6rbereda en attack med ett k\u00e4nt nonce-v\u00e4rde. Utan nonce tvingas angripare kringg\u00e5 hela CSP, vilket \u00e4r avsev\u00e4rt sv\u00e5rare.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"steg-12-testa-och-verifiera-sakerhetshuvudena\">Steg 12: Testa och verifiera s\u00e4kerhetshuvudena<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Verifiera att alla headers s\u00e4tts korrekt med curl och Mozillas Observatory-verktyg. En korrekt konfigurerad app ska inte avsl\u00f6ja serverinformation och ska ha alla kritiska s\u00e4kerhetshuvuden p\u00e5 plats.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Lokal verifiering med curl:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Kontrollera alla headers\ncurl -sI http:\/\/localhost:3000\/ | sort\n\n# Kontrollera specifika headers\ncurl -sI http:\/\/localhost:3000\/ | grep -E \\\n  \"Content-Security-Policy|X-Frame-Options|X-Content-Type|Strict-Transport|Referrer-Policy\"\n\n# Kontrollera att X-Powered-By \u00e4r borttagen\ncurl -sI http:\/\/localhost:3000\/ | grep -i powered\n# Ska ge tomt utdata - ingen X-Powered-By<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Kontrollera med Node.js built-in http-modul:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ test-headers.js\nimport http from 'http';\n\nconst options = {\n  hostname: 'localhost',\n  port: 3000,\n  path: '\/',\n  method: 'GET',\n};\n\nconst req = http.request(options, (res) => {\n  const required = [\n    'content-security-policy',\n    'x-frame-options',\n    'x-content-type-options',\n    'referrer-policy',\n    'cross-origin-opener-policy',\n  ];\n\n  console.log('S\u00e4kerhetshuvuden som hittades:');\n  required.forEach((header) => {\n    const value = res.headers[header];\n    const status = value ? '\u2713' : '\u2717';\n    console.log(`  ${status} ${header}: ${value || 'SAKNAS'}`);\n  });\n\n  const powered = res.headers['x-powered-by'];\n  console.log(`\\nX-Powered-By ${powered ? '\u2717 L\u00c4CKER INFO: ' + powered : '\u2713 borttagen'}`);\n});\n\nreq.end();<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00f6r produktion, k\u00f6r Mozillas Observatory-scanner p\u00e5 <a href=\"https:\/\/observatory.mozilla.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">observatory.mozilla.org<\/a>. Den analyserar din app mot 12 s\u00e4kerhetskriterier och ger ett betyg fr\u00e5n F till A+. En korrekt Helmet-konfiguration ger vanligtvis betyg B eller A direkt, med m\u00f6jlighet att n\u00e5 A+ med HSTS-preload och strict nonce-baserad CSP.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"5-vanliga-misstag-med-helmet-js\">5 vanliga misstag med Helmet.js<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet.js \u00e4r enkelt att installera men l\u00e4tt att konfigurera fel. De h\u00e4r felen ser vi mest i produktionsappar.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Misstag 1: Anropa helmet() efter routes<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Om du anropar <code>app.use(helmet())<\/code> efter att du definierat dina routes g\u00e4ller s\u00e4kerhetshuvudena inte f\u00f6r de routes som definierats f\u00f6re helmet-anropet. Express-middleware k\u00f6rs i den ordning du definierar dem. Helmet m\u00e5ste vara det f\u00f6rsta middleware i kedjan, direkt efter att du skapat Express-appen.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ FEL: Helmet efter routes\napp.get('\/api\/users', handler);\napp.use(helmet()); \/\/ P\u00e5verkar INTE \/api\/users\n\n\/\/ R\u00c4TT: Helmet f\u00f6re routes\napp.use(helmet());\napp.get('\/api\/users', handler);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Misstag 2: Aktivera HSTS-preload utan fullst\u00e4ndigt HTTPS-st\u00f6d<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">HSTS-preload \u00e4r irreversibelt i 1 \u00e5r efter att du registrerat dig. Om en subdom\u00e4n saknar HTTPS-certifikat och du har <code>includeSubDomains: true<\/code> och <code>preload: true<\/code>, l\u00e5ser du ut anv\u00e4ndare fr\u00e5n den subdom\u00e4nen permanent tills preload-listan uppdateras (vilket kan ta m\u00e5nader). Kontrollera att alla subdom\u00e4ner har giltiga certifikat innan du aktiverar preload.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Misstag 3: L\u00e4gga till &#8216;unsafe-inline&#8217; i script-src f\u00f6r att l\u00f6sa CSP-fel<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Det \u00e4r lockande att l\u00f6sa CSP-blockeringsfel genom att l\u00e4gga till <code>'unsafe-inline'<\/code> i <code>script-src<\/code>. Det omintetg\u00f6r hela syftet med CSP och \u00f6ppnar upp f\u00f6r XSS-attacker. R\u00e4tt l\u00f6sning \u00e4r antingen att flytta inline-skript till externa filer eller att implementera nonces (se steg 11).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ FEL: Omintetg\u00f6r XSS-skyddet\nscriptSrc: [\"'self'\", \"'unsafe-inline'\"],\n\n\/\/ R\u00c4TT: Anv\u00e4nd nonces\nscriptSrc: [\"'self'\", (req, res) => `'nonce-${res.locals.cspNonce}'`],<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Misstag 4: Aktivera HSTS lokalt<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Om du aktiverar HSTS under lokal utveckling (localhost) och sedan provar att komma \u00e5t appen via HTTP p\u00e5 samma port senare, kan webbl\u00e4saren v\u00e4gra HTTP-anslutningen i upp till 180 dagar. Inaktivera alltid HSTS i development-milj\u00f6n med en NODE_ENV-kontroll.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Misstag 5: Gl\u00f6mma att konfigurera CSP f\u00f6r Single-Page Applications<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">React, Vue och Angular-appar anv\u00e4nder ofta eval() f\u00f6r hot-reloading under utveckling och kan beh\u00f6va inline-stilar f\u00f6r CSS-in-JS-l\u00f6sningar. Helmets standard-CSP blockerar b\u00e5da. Utan en milj\u00f6specifik CSP-konfiguration fungerar appen i produktion men inte under utveckling, eller vice versa.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ CSP f\u00f6r React\/Vue i development\nconst devDirectives = isDev ? {\n  scriptSrc: [\"'self'\", \"'unsafe-eval'\"], \/\/ Hot-reload kr\u00e4ver eval\n  styleSrc: [\"'self'\", \"'unsafe-inline'\"], \/\/ CSS-in-JS\n} : {};\n\nexport const helmetConfig = helmet({\n  contentSecurityPolicy: {\n    useDefaults: true,\n    directives: {\n      ...devDirectives,\n      \/\/ Produktionsdirektiv skriver alltid \u00f6ver dev-direktivet\n      ...(isDev ? {} : {\n        scriptSrc: [\"'self'\"],\n        styleSrc: [\"'self'\"],\n      }),\n    },\n  },\n});<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"felsokning-8-vanliga-problem-och-losningar\">Fels\u00f6kning: 8 vanliga problem och l\u00f6sningar<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">De h\u00e4r problemen dyker upp i produktionsmilj\u00f6er och kan vara sv\u00e5ra att sp\u00e5ra utan en systematisk approach.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Problem 1: Bilder fr\u00e5n CDN laddas inte<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Symtom: Bilder fr\u00e5n Cloudflare, AWS S3 eller liknande visas inte. Webbl\u00e4sarens konsol visar CSP-fel som &#8220;Refused to load the image because it violates the following Content Security Policy directive: img-src &#8216;self&#8217; data:&#8221;. L\u00f6sning: L\u00e4gg till CDN-dom\u00e4nen i <code>imgSrc<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>imgSrc: [\"'self'\", \"data:\", \"https:\/\/cdn.dinapp.se\", \"https:\/\/*.cloudfront.net\"],<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Problem 2: Tredjepartsfonter visas inte<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Google Fonts, Adobe Fonts och liknande kr\u00e4ver att du till\u00e5ter deras CDN-dom\u00e4ner i b\u00e5de <code>fontSrc<\/code> och <code>styleSrc<\/code>. En vanlig miss \u00e4r att bara l\u00e4gga till dom\u00e4nen i ett av direktiven.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>styleSrc: [\"'self'\", \"https:\/\/fonts.googleapis.com\"],\nfontSrc: [\"'self'\", \"https:\/\/fonts.gstatic.com\"], \/\/ Gl\u00f6ms ofta<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Problem 3: WebSocket-anslutningar blockeras<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">WebSocket-anslutningar (Socket.io, native WebSocket) kr\u00e4ver att <code>connectSrc<\/code> inkluderar r\u00e4tt protokoll (<code>ws:\/\/<\/code> eller <code>wss:\/\/<\/code>).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>connectSrc: [\"'self'\", \"ws:\/\/localhost:3000\", \"wss:\/\/api.dinapp.se\"],<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Problem 4: Stripe eller Braintree-betalningar fungerar inte<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Betaltj\u00e4nster laddar iframe:ar och skript fr\u00e5n externa dom\u00e4ner. Stripe kr\u00e4ver att du till\u00e5ter <code>https:\/\/js.stripe.com<\/code> och <code>https:\/\/hooks.stripe.com<\/code> i <code>scriptSrc<\/code> och <code>frameSrc<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>scriptSrc: [\"'self'\", \"https:\/\/js.stripe.com\"],\nframeSrc: [\"'self'\", \"https:\/\/js.stripe.com\", \"https:\/\/hooks.stripe.com\"],\nconnectSrc: [\"'self'\", \"https:\/\/api.stripe.com\"],<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Problem 5: React hot-reload (HMR) slutar fungera<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vite och Create React App anv\u00e4nder eval() och inline-skript under hot-reload. L\u00f6sning: Detektera development-milj\u00f6n och till\u00e5t <code>'unsafe-eval'<\/code> enbart i development (se steg 4 och pitfall 5 ovan).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Problem 6: X-Powered-By fortfarande synlig<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Om <code>X-Powered-By: Express<\/code> fortfarande syns i svarsrubrikerna, kontrollera om du explicit satt headern n\u00e5gonstans i koden. Helmet tar bort den via Express inbyggda <code>app.disable('x-powered-by')<\/code>, men om din kod s\u00e4tter om headern manuellt vinner den. Helmet f\u00f6rhindrar inte aktivt att du s\u00e4tter om den.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Problem 7: CORS-fel efter Helmet-installation<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet p\u00e5verkar inte CORS-headers direkt, men <code>Cross-Origin-Resource-Policy: same-origin<\/code> kan orsaka att API-svar blockeras n\u00e4r ett separat front-end-projekt f\u00f6rs\u00f6ker h\u00e4mta data. L\u00f6sning f\u00f6r separata front-end\/back-end-projekt:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import cors from 'cors';\n\n\/\/ CORS-konfiguration F\u00d6RE Helmet\napp.use(cors({ origin: 'https:\/\/app.dinapp.se' }));\n\n\/\/ \u00c4ndra CORP f\u00f6r API-routes\napp.use('\/api', helmet({\n  crossOriginResourcePolicy: { policy: 'same-site' },\n}));<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Problem 8: CSP-rapport\u00f6versv\u00e4mning i loggarna<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Om du aktiverar CSP:s report-to-direktiv utan att ha en rapportmottagare konfigurerad, eller om din CSP \u00e4r f\u00f6r restriktiv, kan du f\u00e5 tusentals CSP-rapporter per sekund. Aktivera Report-Only-l\u00e4get under testning f\u00f6r att samla rapporter utan att blockera resurser:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export const helmetConfig = helmet({\n  contentSecurityPolicy: {\n    useDefaults: true,\n    \/\/ Report-Only: Rapporterar men blockerar INTE\n    reportOnly: isDev, \/\/ S\u00e4tt till false i produktion\n    directives: {\n      reportTo: 'csp-endpoint',\n    },\n  },\n});<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"avancerade-tekniker\">Avancerade tekniker<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">N\u00e4r du beh\u00e4rskar grundkonfigurationen finns ytterligare tekniker f\u00f6r att maximera s\u00e4kerheten i komplexa applikationer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Route-specifik Helmet-konfiguration<\/strong>: Olika delar av din app kan beh\u00f6va olika CSP-regler. Admin-panelen kan ha en striktare CSP \u00e4n den publika hemsidan.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import helmet from 'helmet';\n\nconst strictHelmet = helmet({\n  contentSecurityPolicy: {\n    useDefaults: true,\n    directives: { scriptSrc: [\"'self'\"] },\n  },\n});\n\nconst relaxedHelmet = helmet({\n  contentSecurityPolicy: {\n    useDefaults: true,\n    directives: {\n      scriptSrc: [\"'self'\", \"https:\/\/cdn.jsdelivr.net\"],\n      styleSrc: [\"'self'\", \"https:\", \"'unsafe-inline'\"],\n    },\n  },\n});\n\n\/\/ Strikt CSP f\u00f6r admin\napp.use('\/admin', strictHelmet);\n\n\/\/ Mer till\u00e5tande CSP f\u00f6r publika sidor med CDN-resurser\napp.use('\/public', relaxedHelmet);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>CSP-hashing ist\u00e4llet f\u00f6r nonces<\/strong>: Om inline-skript inte \u00e4ndras mellan f\u00f6rfr\u00e5gningar kan du anv\u00e4nda SHA-256-hashen av skriptets inneh\u00e5ll ist\u00e4llet f\u00f6r nonces. Ber\u00e4kna hashen och l\u00e4gg till den i CSP-konfigurationen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import crypto from 'crypto';\n\n\/\/ Ber\u00e4kna SHA-256-hash av inline-skriptets inneh\u00e5ll\nconst inlineScript = \"console.log('H\u00e4lsning');\";\nconst hash = crypto.createHash('sha256')\n  .update(inlineScript)\n  .digest('base64');\n\n\/\/ L\u00e4gg till hashen i scriptSrc\nscriptSrc: [\"'self'\", `'sha256-${hash}'`],<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Integration med loggning och \u00f6vervakning<\/strong>: S\u00e4tt upp CSP-rapportering till en endpoint som loggar eller alertar p\u00e5 CSP-brott i produktion. Det hj\u00e4lper dig identifiera XSS-attackf\u00f6rs\u00f6k och felkonfigurerad CSP.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"komplett-projekt-med-alla-12-steg\">Komplett projekt med alla 12 steg<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">H\u00e4r \u00e4r den kompletta applikationen som integrerar alla steg i guiden. Kopiera och klistra in f\u00f6r ett fullt fungerande produktionsklart projekt.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ src\/middleware\/security.js - Komplett Helmet-konfiguration\nimport helmet from 'helmet';\nimport crypto from 'crypto';\n\nconst isDev = process.env.NODE_ENV === 'development';\n\nexport function createSecurityMiddleware() {\n  const nonceMiddleware = (req, res, next) => {\n    res.locals.cspNonce = crypto.randomBytes(16).toString('base64');\n    next();\n  };\n\n  const helmetMiddleware = helmet({\n    \/\/ 1. Content Security Policy\n    contentSecurityPolicy: {\n      useDefaults: true,\n      reportOnly: isDev,\n      directives: {\n        defaultSrc: [\"'self'\"],\n        scriptSrc: [\n          \"'self'\",\n          isDev ? \"'unsafe-eval'\" : null,\n          (req, res) => `'nonce-${res.locals.cspNonce}'`,\n        ].filter(Boolean),\n        styleSrc: [\"'self'\", \"https:\", \"'unsafe-inline'\"],\n        imgSrc: [\"'self'\", \"data:\", \"https:\"],\n        fontSrc: [\"'self'\", \"https:\", \"data:\"],\n        connectSrc: [\"'self'\"],\n        objectSrc: [\"'none'\"],\n        frameAncestors: [\"'self'\"],\n        baseUri: [\"'self'\"],\n        formAction: [\"'self'\"],\n        upgradeInsecureRequests: isDev ? null : [],\n      },\n    },\n\n    \/\/ 2. HSTS\n    strictTransportSecurity: isDev ? false : {\n      maxAge: 31536000,\n      includeSubDomains: true,\n      preload: true,\n    },\n\n    \/\/ 3. Clickjacking\n    frameguard: { action: 'sameorigin' },\n\n    \/\/ 4. MIME-sniffning\n    noSniff: true,\n\n    \/\/ 5. Referrer\n    referrerPolicy: { policy: 'strict-origin-when-cross-origin' },\n\n    \/\/ 6. Cross-Origin isolation\n    crossOriginOpenerPolicy: { policy: 'same-origin' },\n    crossOriginResourcePolicy: { policy: 'same-origin' },\n\n    \/\/ 7. DNS-prefetch\n    dnsPrefetchControl: { allow: false },\n\n    \/\/ 8. X-Powered-By tas bort automatiskt\n    hidePoweredBy: true,\n  });\n\n  return [nonceMiddleware, helmetMiddleware];\n}\n\n\/\/ src\/app.js - Komplett Express-app\nimport express from 'express';\nimport { createSecurityMiddleware } from '.\/middleware\/security.js';\nimport 'dotenv\/config';\n\nconst app = express();\nconst PORT = process.env.PORT || 3000;\n\n\/\/ S\u00e4kerhetsmiddleware F\u00d6RST\napp.use(...createSecurityMiddleware());\n\n\/\/ Body parsers\napp.use(express.json({ limit: '10kb' }));\napp.use(express.urlencoded({ extended: true, limit: '10kb' }));\n\n\/\/ Routes\napp.get('\/health', (req, res) => {\n  res.json({\n    status: 'OK',\n    env: process.env.NODE_ENV,\n    timestamp: new Date().toISOString(),\n  });\n});\n\napp.get('\/', (req, res) => {\n  res.send(`<!DOCTYPE html>\n<html lang=\"sv\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Helmet.js Demo<\/title>\n<\/head>\n<body>\n  <h1>Helmet.js skyddar den h\u00e4r sidan<\/h1>\n  <script nonce=\"${res.locals.cspNonce}\">\n    console.log('Inline-skript med nonce fungerar!');\n    document.querySelector('h1').style.color = '#2563eb';\n  <\/script>\n<\/body>\n<\/html>`);\n});\n\n\/\/ Felhantering\napp.use((err, req, res, next) => {\n  console.error(err.stack);\n  res.status(500).json({ error: 'Internt serverfel' });\n});\n\napp.listen(PORT, () => {\n  console.log(`S\u00e4ker server startar p\u00e5 http:\/\/localhost:${PORT}`);\n  console.log(`Milj\u00f6: ${process.env.NODE_ENV || 'development'}`);\n});<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Skapa en <code>.env<\/code>-fil f\u00f6r konfiguration:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PORT=3000\nNODE_ENV=production<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Starta och verifiera:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npm start\ncurl -sI http:\/\/localhost:3000\/ | grep -c \"security\\|frame\\|content\\|referrer\\|strict\"\n# F\u00f6rv\u00e4ntat utdata: 5 eller fler matchningar<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"relaterade-artiklar\">Relaterade artiklar<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"fordjupa-din-node-js-sakerhet\">F\u00f6rdjupa din Node.js-s\u00e4kerhet<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/se\/owasp-top-10-nodejs\/\">OWASP Top 10 i Node.js: 12 steg, 30 min [2026]<\/a> &#8211; T\u00e4cker alla tio OWASP-risker med Node.js-kod.<\/li>\n<li><a href=\"\/se\/nodejs-input-validation\/\">Node.js Indatavalidering: 12 steg mot injektionsattacker [2026]<\/a> &#8211; Validering med Zod och Joi mot injektionsattacker.<\/li>\n<li><a href=\"\/se\/oauth2-pkce-nodejs\/\">OAuth 2.0 med PKCE i Node.js: 12 steg, 30 min [2026]<\/a> &#8211; Implementera s\u00e4ker OAuth-autentisering.<\/li>\n<li><a href=\"\/se\/ecdh-nyckelutbyte-nodejs\/\">ECDH i Node.js: Elliptisk Kurva Diffie-Hellman i 12 steg [2026]<\/a> &#8211; Kryptografisk nyckelutv\u00e4xling i Node.js.<\/li>\n<li><a href=\"\/se\/blake3-hashing-nodejs\/\">BLAKE3 i Node.js: 5x Snabbare Hash \u00e4n SHA-256 i 12 Steg [2026]<\/a> &#8211; N\u00e4sta generations hashfunktion i Node.js.<\/li>\n<li><a href=\"\/se\/openssl-nycklar-certifikat\/\">OpenSSL 3.5: nycklar och certifikat i 12 steg [2026]<\/a> &#8211; TLS-certifikat och nycklar med OpenSSL.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"vanliga-fragor\">Vanliga fr\u00e5gor<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Kan Helmet.js anv\u00e4ndas med NestJS och Fastify?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ja. NestJS har inbyggt st\u00f6d f\u00f6r Helmet via <code>app.use(helmet())<\/code> i main.ts. Fastify har ett eget paket, <code>@fastify\/helmet<\/code>, som ger samma funktionalitet med Fastify-specifik middleware-integration. Konfigurationsoptionerna \u00e4r identiska.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hur p\u00e5verkar Helmet.js prestanda?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet.js l\u00e4gger till en minimal m\u00e4ngd arbete per f\u00f6rfr\u00e5gan, i praktiken mikrosekunder per request. Det arbetar enbart med HTTP-headers och utf\u00f6r inga externa anrop, databass\u00f6kningar eller tung ber\u00e4kning. I benchmarks m\u00e4rks inte Helmet-overhead i m\u00e4tningar p\u00e5 applikationsniv\u00e5.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Ska jag anv\u00e4nda Helmet i test-milj\u00f6er?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Det beror p\u00e5 testtypen. Integrationstester och end-to-end-tester b\u00f6r k\u00f6ras med Helmet aktiverat f\u00f6r att verifiera att s\u00e4kerhetskonfigurationen fungerar korrekt. Enhetstester av enskilda funktioner beh\u00f6ver s\u00e4llan Helmet. Inaktivera HSTS och eventuellt CSP i testmilj\u00f6er f\u00f6r att f\u00f6renkla testskrivning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>R\u00e4cker Helmet.js f\u00f6r att g\u00f6ra min app s\u00e4ker?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Nej. Helmet.js hanterar HTTP-s\u00e4kerhetshuvuden och \u00e4r ett viktigt lager i s\u00e4kerhetsarbetet, men det ers\u00e4tter inte indatavalidering, parametriserade databasfr\u00e5gor, s\u00e4ker autentisering, rate limiting och regelbundna s\u00e4kerhetsgranskningar. Se Helmet som ett av flera skyddslagret i en &#8220;defense in depth&#8221;-strategi.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Vilken \u00e4r skillnaden mellan Helmet och en WAF (Web Application Firewall)?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Helmet s\u00e4tter HTTP-svarshuvuden som instruerar webbl\u00e4saren om s\u00e4kerhetspolicyer. En WAF analyserar inkommande trafik och blockerar skadliga f\u00f6rfr\u00e5gningar p\u00e5 n\u00e4tverksniv\u00e5 innan de n\u00e5r din app. De kompletterar varandra. Helmet skyddar klientsidan, WAF:en skyddar serversidan.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fungerar CSP med \u00e4ldre webbl\u00e4sare?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">CSP Level 3 st\u00f6ds av alla moderna webbl\u00e4sare (Chrome 59+, Firefox 58+, Safari 15.4+, Edge 79+). Internet Explorer saknar st\u00f6d f\u00f6r CSP Level 2 och Level 3. Om du fortfarande st\u00f6der IE, kontrollera att din CSP inte inneh\u00e5ller direktiv som IE tolkar fel, och testa noggrant. Helmet s\u00e4tter X-XSS-Protection till 0 (inaktiverat) f\u00f6r moderna webbl\u00e4sare eftersom den \u00e4ldre XSS-filterfunktionen kan utnyttjas av angripare.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hur uppdaterar jag Helmet.js s\u00e4kert?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">K\u00f6r <code>npm outdated helmet<\/code> regelbundet f\u00f6r att kontrollera om uppdateringar finns. L\u00e4s release notes p\u00e5 <a href=\"https:\/\/helmetjs.github.io\/\" target=\"_blank\" rel=\"noopener noreferrer\">helmetjs.github.io<\/a> f\u00f6re uppgradering. Major-versioner kan \u00e4ndra standardv\u00e4rden f\u00f6r headers, vilket kan bryta din app om du f\u00f6rlitar dig p\u00e5 specifika standardv\u00e4rden utan explicit konfiguration. Uppgradera i staging-milj\u00f6n och testa noggrant med curl och Observatory-scanner innan du drifts\u00e4tter i produktion.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Beh\u00f6ver jag Helmet om min app ligger bakom en omv\u00e4nd proxy som Nginx?<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ja. Nginx kan s\u00e4tta HSTS och X-Frame-Options, men CSP och nonce-hantering \u00e4r applikationsspecifika och kr\u00e4ver att din Node.js-app hanterar dem. Det \u00e4r dessutom b\u00e4sta praxis att ha s\u00e4kerhetshuvuden p\u00e5 applikationsniv\u00e5 s\u00e5 att de g\u00e4ller oavsett vilken infrastruktur som anv\u00e4nds. Helmet och Nginx-konfiguration \u00e4r komplement\u00e4ra, inte alternativ.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Helmet.js \u00e4r ett Express-middleware som automatiskt s\u00e4tter 13 HTTP-svarshuvuden och skyddar din Node.js-applikation mot XSS, clickjacking, MIME-sniffning och HTTPS-nedgradering. En enda rad kod, app.use(helmet()), aktiverar alla skydd p\u00e5 en g\u00e5ng.\u2026<\/p>\n","protected":false},"author":7,"featured_media":157,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,3],"tags":[],"class_list":["post-156","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-10","category-security"],"_links":{"self":[{"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/posts\/156","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/comments?post=156"}],"version-history":[{"count":1,"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/posts\/156\/revisions"}],"predecessor-version":[{"id":158,"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/posts\/156\/revisions\/158"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/media\/157"}],"wp:attachment":[{"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/media?parent=156"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/categories?post=156"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/shattered.io\/se\/wp-json\/wp\/v2\/tags?post=156"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}