Skip to main content

HTTP Strict Transport Security (HSTS)-Header sollten in Ihrem Node.js-Server zum Einsatz kommen

Artikel von

Raphael Mun

feature global security

29. Dezember 2022

0 Min. Lesezeit

Bei den meisten Websites und Apps ist der Einsatz sicherheitsrelevanter HTTP-Header mittlerweile Standard. Websites verwenden Header in HTTP-Anfragen und -Antworten, um Informationen zu einer Seite oder zu über das HTTP-Protokoll gesendeten Daten zu übermitteln. So kann ein Content-Encoding-Header beispielsweise angeben, dass der Inhalt eine komprimierte ZIP-Datei ist, oder ein Location-Header eine Weiterleitungs-URL festlegen.

Unter den zahlreichen Security-Headern, die moderne Webbrowser zum Schutz ihrer Nutzer einsetzen, ist der HTTP-Strict-Transport-Security-Header (HSTS) besonders wichtig. Mit dem HSTS-Header weist eine Website den Browser an, bei jedem späteren Besuch das HTTPS-Protokoll zu verwenden.

Trotz ihres Nutzens, der einfachen Implementierung und der Unterstützung durch praktisch alle Browser enthalten nur etwa 25 % der mobilen und 28 % der Desktop-HTTP-Antworten HSTS-Header.

Sehen wir uns HSTS-Header genauer an, um herauszufinden, wie sie die Websicherheit beeinflussen und warum sie in Node.js eingesetzt werden sollten. Anschließend erfahren Sie, wie Sie HSTS in einem Node.js-Server aktivieren.

Warum sollten Sie HSTS aktivieren?

HTTPS-Verbindungen sind sicher, weil sie übertragene Datenpakete mithilfe von SSL/TLS-Zertifikaten ver- und entschlüsseln, die von bekannten Zertifizierungsstellen (CAs) überprüft werden können. Dadurch können nur der Computer des Nutzers und der Server die übertragenen Datenpakete lesen – unabhängig davon, wer den Netzwerkverkehr abfängt.

Typische HTTP-Verbindungen sind unverschlüsselt. Das bedeutet, dass jeder, der auf die Daten zugreift, sie lesen kann. Zu diesen unbeabsichtigten Empfängern zählen Server, die die Daten des Nutzers an den Zielserver weiterleiten, oder Hacker, die den Netzwerkverkehr über einen öffentlichen WLAN-Router abfangen.

Sehen Sie sich dazu die Ergebnisse des Web-Almanac-Berichts 2022 an, an dem auch Snyk mitgewirkt hat.

Diagramme aus dem Web Almanac 2022: 25 % der mobilen Anfragen enthalten einen HSTS-Header; außerdem werden die Nutzungsraten von HSTS-Direktiven auf Desktop- und Mobilgeräten dargestellt.

Derzeit enthalten nur 34 % der mobilen und 37 % der Desktop-Antworten auf Anfragen die includeSubdomain-Direktive.

Die große Mehrheit ist daher weiterhin anfälliger für Man-in-the-Middle- (MITM-)Angriffe. Diese können von Kreditkarten- oder Identitätsdiebstahl bis hin zu kompromittierten Web-Zugangsdaten für unsere Node.js-Webanwendung führen. Wichtig ist: Angreifer müssen die Daten nicht genau in dem Moment abfangen, in dem wir unsere Anmeldedaten eingeben. Browser-Cookies speichern und senden häufig unsere Sitzungs- und Zugriffstoken. So können Angreifer sie durch Session-Hijacking erlangen.

Wie funktioniert HSTS?

Enthält der HTTP-Antwortheader einen HSTS-Header, wissen Webbrowser, dass sie stets eine HTTPS-Verbindung zum Server verwenden müssen. Nutzer, die sich zuerst über HTTP verbunden haben, werden automatisch weitergeleitet. Von da an bleiben die Verbindungen zur Webanwendung oder Website verschlüsselt und sicher. So kann die App sichere Cookies verwenden, und MITM-Angriffe werden erschwert.

Der HSTS-Header bietet drei verschiedene Parameter. Sehen wir sie uns an.

max - age = <expire-time>

Dieser erforderliche Parameter gibt in Sekunden an, wie lange der Browser sich merken soll, die Website über HTTPS aufzurufen. Nach Ablauf dieser Zeit lädt der Browser die Website beim nächsten Besuch wie gewohnt. Jedes Mal, wenn der Browser den HSTS-Header empfängt, wird die Ablaufzeit aktualisiert. Dadurch kann der Parameter unbegrenzt aktiv bleiben. Alternativ können bestimmte Websites HSTS sofort deaktivieren, indem sie diesen Wert auf 0 setzen.

Beim Testen Ihrer HSTS-Konfiguration können Sie eine kurze Dauer festlegen, beispielsweise 300 Sekunden (fünf Minuten). Sobald Sie überprüft haben, dass Ihre Website ordnungsgemäß funktioniert, können Sie die Dauer verlängern, etwa auf 31.536.000 Sekunden (ein Jahr).

includeSubDomains

Der Parameter includeSubDomains ist eine optionale Direktive, die den Browser anweist, HSTS für die Website und alle ihre Subdomains zu aktivieren. Da diese Einstellung umfassend gilt, sollten Sie vor der Implementierung sicherstellen, dass alle Ihre Subdomains HTTPS unterstützen.

preload

Bei einer ersten Verbindung könnte möglicherweise eine manipulierte HTTP-Verbindung zum Einsatz kommen. Als Gegenmaßnahme pflegt Google den inoffiziellen Parameter preload. Die meisten großen Browser unterstützen diesen Security-Header, der das Risiko erheblich verringert. Eine Website kann den Parameter preload zum HSTS-Header hinzufügen und die Domain anschließend beim Preload-Dienst registrieren. Browser können dann diese Referenzliste prüfen, um festzustellen, ob bereits die erste Verbindung über HTTPS erfolgen kann. Damit der Parameter preload funktioniert, muss der Wert für max-age mindestens 31.536.000 Sekunden betragen und der Parameter includeSubDomains aktiviert sein.

Beachten Sie, dass die Bearbeitung eines Antrags auf Entfernung mehrere Monate dauern kann, sobald der Preload-Dienst Ihre Domain hinzugefügt hat. Wenn Sie Ihre Domain für das Preloading registrieren möchten, sollten Sie sich mit den Anforderungen für die Einreichung und den Empfehlungen für die Bereitstellung vertraut machen.

Sicherheit mit HSTS verbessern

Sehen wir uns an, wie Sie mit einem Node.js-Servercode auf einen HSTS-Header antworten. Alle Codebeispiele in diesem Artikel sind öffentlich verfügbar und finden sich im folgenden Open-Source-Repository auf GitHub.

Voraussetzungen

Für dieses Projekt benötigen Sie Folgendes:

  • Einen registrierten Domainnamen

  • Einen Server mit Node.js und verfügbaren Netzwerkports 80 und 433

  • Einen funktionsfähigen DNS-Eintrag für die Domain, der auf den Server verweist

Ein SSL/TLS-Zertifikat abrufen

Bevor Sie HTTPS aktivieren können, benötigen Sie ein Zertifikat und einen privaten Schlüssel für die Domain. Falls Sie noch keines haben, können Sie es über Let’s Encrypt mit den folgenden Schritten abrufen:

Installieren Sie zunächst certbot, indem Sie dieser Anleitung folgen. Wählen Sie im Dropdown-Menü Software die Option other und im Dropdown-Menü System das Betriebssystem Ihres Servers. Folgen Sie dann den angezeigten Anweisungen.

Certbot-Anleitungsseite mit Auswahlmöglichkeiten für eine HTTP-Website auf „Other“ und CentOS 8.

Stellen Sie als Nächstes sicher, dass die Ports 80 und 443 auf dem Server geöffnet sind, und führen Sie den folgenden Befehl mit Ihrer Serverdomain aus:

certbot certonly --standalone -d your.domain.url

Möglicherweise müssen Sie dem Befehl sudo voranstellen und ihn mit privilegierten Benutzerrechten ausführen.

Terminalausgabe, die zeigt, dass Certbot erfolgreich ein HTTPS-Zertifikat von Let's Encrypt für snykdemo.instafluff.tv bezogen und gespeichert hat.

Führen Sie nun certbot certificates aus (bei Bedarf mit sudo), um die Dateipfade des Zertifikats und des privaten Schlüssels abzurufen.

Terminal mit Certbot-Ausgabe für das Zertifikat von snykdemo.instafluff.tv, einschließlich Ablaufdatum sowie Pfaden zum Let's-Encrypt-Zertifikat und zum privaten Schlüssel.

Servercode einrichten

Erstellen Sie zunächst einen Projektordner auf dem Server, indem Sie den Befehl mkdir snyk-demo ausführen.

Wechseln Sie anschließend mit cd snyk-demo in den Ordner.

Initialisieren Sie den Ordner dann mit npm init -y als Node.js-Projekt.

Terminal, in dem npm init eine package.json-Datei für das Node.js-Projekt snyk-demo erstellt.

Installieren Sie nun einige Projektabhängigkeiten für den Server. Folgen Sie dabei den passenden Anweisungen für Express oder Fastify.

Express:

npm install express helmet

Fastify:

npm install fastify @fastify/helmet

Jetzt können wir einen einfachen Express-Node.js-Server erstellen, der HTTP und HTTPS verwendet.

Erstellen Sie in diesem Ordner eine Datei namens index.js und fügen Sie am Anfang des Codes die folgenden Node-Module hinzu.

Express:

const fs = require( "fs" );
const http = require( "http" );
const https = require( "https" );
const express = require( "express" );
const helmet = require( "helmet" );

Fastify:

const fs = require( "fs" );
const helmet = require( "@fastify/helmet" );

Fügen Sie den folgenden Code hinzu, um die Zertifikatsdateien zu laden, und ersetzen Sie den Wert von certificatePath durch den Pfad zum Zertifikat Ihrer Domain. Wenn Sie certbot von Let’s Encrypt verwendet haben, können Sie mit certbot certificates die Dateipfade abrufen.

Express:

// Replace the following with your domain certificate path
const certificatePath = `/etc/letsencrypt/live/snykdemo.instafluff.tv/;
const privateKey = fs.readFileSync( `${certificatePath}/privkey.pem, "utf8" );
const certificate = fs.readFileSync( `${certificatePath}/fullchain.pem, "utf8" );
// Add the following if your certificate includes a certificate chain
// const ca = fs.readFileSync( `${certificatePath}/chain.pem, "utf8" );

const credentials = {
    key: privateKey,
    cert: certificate,
    // ca: ca, // Add the ca if there is a certificate chain
};

Fastify:

// Replace the following with your own domain certificate path
const certificatePath = `/etc/letsencrypt/live/snykdemo.instafluff.tv/`;
const fastify = require( "fastify" )({
    https: {
        key: fs.readFileSync( `${certificatePath}/privkey.pem, "utf8" ),
        cert: fs.readFileSync( `${certificatePath}/fullchain.pem, "utf8" ),
        // // Add the following if your certificate includes a certificate chain
        // ca: fs.readFileSync( `${certificatePath}/chain.pem, "utf8" ),
    },
});
const fastifyHttp = require( "fastify" )();

Initialisieren Sie nun die Express-/Fastify-App und erstellen Sie eine einfache Route.

Der folgende Code zeigt alle drei HSTS-Parameter. Für den Anfang können Sie jedoch auch nur den Parameter max-age verwenden.

Option 1: Helmet-Middleware verwenden

HSTS lässt sich zunächst über die Helmet-Middleware bei der App-Initialisierung einrichten:

Express:

const app = express();
app.use( helmet() );
app.use( helmet.hsts( { maxAge: 300, includeSubDomains: true, preload: true } ) );

app.use( ( req, res ) => {
res.send( "Hello secure web!" );
});

Fastify:

const hsts = { maxAge: 300, includeSubDomains: true, preload: true };
fastify.register( helmet, { hsts } );
fastifyHttp.register( helmet, { hsts } );

Option 2: Header manuell festlegen

Alternativ können Sie den HSTS-Header manuell über eine Middleware festlegen, die ihn auf jede Antwort anwendet:

Express:

const app = express();

app.use( ( req, res ) => {
    if( req.secure ) {
         res.setHeader( "Strict-Transport-Security", "max-age=300; includeSubDomains; preload" );
    }
    res.send( "Hello secure web!" );
});

Fastify:

fastify.get( "/", ( req, res ) => {
    res.header( "Strict-Transport-Security", "max-age=300; includeSubDomains; preload" );
    res.send( "Hello secure web!" );
});
fastifyHttp.get( "/", ( req, res ) => {
    res.header( "Strict-Transport-Security", "max-age=300; includeSubDomains; preload" );
    res.send( "Redirect to HTTPS" );
});

Zum Abschluss erstellen Sie mit dem folgenden Code die HTTP- und HTTPS-Server:

Express:

const httpServer = http.createServer( app );
httpServer.listen( 80, () => {
console.log( "HTTP server started." );
});

const httpsServer = https.createServer( credentials, app );
httpsServer.listen( 443, () => {
console.log( "HTTPS server started" );
});

Fastify:

fastifyHttp.listen( { port: 80, host: "0.0.0.0" }, ( err, address ) => {
    console.log( "HTTP server started" );
});

fastify.listen( { port: 443, host: "0.0.0.0" }, ( err, address ) => {
    console.log( "HTTPS server started" );
});

Hier finden Sie die Links zu den Code-Repositories der Express- und Fastify-Projekte.

Führen Sie schließlich den Servercode mit node index.js aus und öffnen Sie anschließend Ihre Domain in einem Webbrowser.

bitnami@ip-172-26-14-29:~/snyk-demo$ sudo node index.js
HTTP server started.
HTTPS server started

Öffnen Sie die DevTools Ihres Browsers und überprüfen Sie die Antwortheader im Tab Network. Dort sehen Sie, dass der HSTS-Header angegeben ist.

Chrome DevTools: Netzwerk-Header mit dem Strict-Transport-Security-Antwort-Header und max-age=300, includeSubDomains und preload

Wie geht es weiter?

Sie wissen nun, warum HTTP-Strict-Transport-Security-Header für die Sicherheit von Node.js-Anwendungen wichtig sind, wie sie MITM-Angriffe verhindern helfen und wie Sie sie in Ihrem Node.js-Code implementieren. Damit verfügen Sie über die nötigen Werkzeuge, um Ihre Webanwendungen für Ihre Nutzer abzusichern.

Ein weiterer wichtiger Punkt: In einer Produktionsumgebung sollten Sie HSTS nicht einrichten und SSL nicht über die Node.js-App bereitstellen. Stattdessen sollten Sie diese Aufgaben an HTTP-Server für statische Dateien wie NGINX oder Apache auslagern.

Weiterlesen

blog feature snyk container custom base recommendations
Blog

Evo Agentic AppSec: Sicherheit, die mit der KI-Entwicklung Schritt hält

KI-gestützte Entwicklung überholt herkömmliche Security-Workflows. Snyk Agentic AppSec setzt Security-Agenten ein, die Schwachstellen kontinuierlich finden, beheben und überprüfen – während Menschen die Maßstäbe festlegen.

blog feature ai violet
Blog

VulnBump: Können KI-Agenten anfällige Abhängigkeiten beheben, ohne den Build zu beschädigen?

VulnBump testet KI-Agenten anhand von 307 realen Dependency-Upgrades. Eine Lösung zählt nur, wenn die Sicherheitslücke behoben ist und Build sowie Tests weiterhin erfolgreich sind.

Blog

Frontier-Modelle fanden die Schwachstellen. Nur der Angreifer fand die Angriffsketten.

Die statische Analyse fand die Schwachstellen, doch erst Live-Angriffstests bewiesen, wie sie sich zu Angriffen verketten lassen. Ein Vergleich von Evo COS, Claude Security und Claude Code Security.