SSL/TLS-Pinning in Node.js implementieren
Nwani Victory
29. August 2023
0 Min. LesezeitDa Angreifer Man-in-the-Middle-Angriffe (MITM) durchführen, reicht ein SSL/TLS-Zertifikat nicht mehr aus, um einer eingehenden Verbindung zu vertrauen. Deshalb setzen Entwickler zunehmend auf SSL/TLS-Pinning, auch Certificate- oder Public-Key-Pinning genannt, um die Authentizität und Integrität einer Verbindung zusätzlich zu bestätigen.
In einer Node.js-Anwendung bietet SSL/TLS-Pinning eine zusätzliche Sicherheitsebene, indem es Angreifer daran hindert, die Kommunikation zwischen Client und Server abzufangen und zu manipulieren.
Dieser Artikel erklärt Certificate-Pinning und beleuchtet dessen Vorteile und Einsatzmöglichkeiten in Node.js-Anwendungen.
Wann und warum Sie SSL/TLS-Pinning verwenden sollten
SSL/TLS-Pinning ist ein Sicherheitsmechanismus, der vor MITM- und anderen zertifikatsbezogenen Angriffen schützt. Dazu stellt es sicher, dass ein Client, beispielsweise eine Node.js-Anwendung, nur eine Verbindung zu einem Server mit einem zuvor verifizierten digitalen Zertifikat herstellt. Bei dieser Technik werden bestimmte Zertifikate oder öffentliche Schlüssel in Host-Anwendungen gespeichert und mit dem öffentlichen Schlüssel oder Zertifikat des Servers verglichen. Die Zertifikate oder öffentlichen Schlüssel können fest in den Anwendungen hinterlegt, über Umgebungsvariablen eingebunden oder für mehr Flexibilität extern in einem Key-Vault-Service gespeichert werden.
Certificate-Pinning verringert das Risiko von MITM-Angriffen, indem es alle Anfragen ohne passendes gepinntes Zertifikat als bösartig einstuft und abbricht – selbst wenn die Anfrage HTTPS verwendet. Außerdem hilft es, andere zertifikatsbezogene Schwachstellen zu verhindern, etwa Zertifikatsfälschung oder -manipulation und kompromittierte Zertifizierungsstellen (CAs).
Laut der Stack Overflow Developer Survey verwenden 47,12 % der Entwickler Node.js. Damit ist es eine etablierte Webtechnologie für serverseitige Anwendungen. In Node.js integrierte Module wie HTTPS bieten zusätzlichen Schutz, indem sie gepinnte Zertifikate validieren. Eine Node.js-Anwendung mit Certificate-Pinning vergleicht das während des TLS-Handshakes präsentierte Zertifikat mit dem vordefinierten Zertifikat oder den öffentlichen Schlüsseln. Bei einer Abweichung bricht sie die Anfrage auf der Transportschicht ab.
Ein Anwendungsfall für Certificate-Pinning sind Finanzanwendungen auf Mobilgeräten. Ein MITM-Angriff auf ein solches Gerät kann für den Besitzer katastrophale Folgen haben, da das Gerät sensible persönliche Daten wie Kreditkarten- oder Kontaktinformationen übertragen könnte. Neuere mobile Betriebssystemversionen wie Android Pie verfügen über Sicherheitsfunktionen, die es Anwendungen nur erlauben, sichere Verbindungen herzustellen. Angreifer könnten jedoch Phishing-Angriffe starten, indem sie selbstsignierte Zertifikate erstellen, um auf das Gerät zuzugreifen. Certificate-Pinning stellt sicher, dass die Anwendung keine nicht vertrauenswürdige Verbindung zulässt, selbst wenn das Gerät dem selbstsignierten Zertifikat vertraut.
Vorbereitung auf die Implementierung von SSL/TLS-Pinning
Wenn ein Client eine Netzwerkanfrage an einen Server sendet, initiiert die Transportschicht einen sicheren Handshake über das SSL/TLS-Protokoll. Der Server präsentiert sein digitales Zertifikat, das den für Verschlüsselung und Authentifizierung verwendeten öffentlichen Schlüssel enthält. Während des Handshakes ruft die Anwendung den öffentlichen Schlüssel des Servers aus dem präsentierten Zertifikat ab.
Die Anwendung vergleicht den abgerufenen öffentlichen Schlüssel mit einer vorkonfigurierten oder fest hinterlegten Kopie. Stimmen die Schlüssel überein, gilt die Verbindung als sicher und die Kommunikation kann fortgesetzt werden. Stimmen sie nicht überein, kann die Anwendung die Verbindung beenden oder gemäß ihrer Sicherheitsrichtlinien geeignete Maßnahmen ergreifen, etwa einen Alarm auslösen oder die Übertragung sensibler Daten verweigern.
CAs spielen eine wichtige Rolle beim Certificate-Pinning, da sie die SSL/TLS-Zertifikate für den Aufbau einer sicheren Verbindung bereitstellen. Die CA signiert das Zertifikat, das bei webbasierten Anwendungen vom Browser oder über die Vertrauenskette des Betriebssystems validiert wird. Certificate-Pinning bietet einen zusätzlichen Schritt, um zu bestätigen, dass dem Zertifikat vertraut werden kann.
TLS ist ein integriertes Modul in Node.js, das von einem Host ein Zertifikatsobjekt mit einem Feld für den öffentlichen Schlüssel extrahieren kann. Der folgende Code zeigt, wie Sie mit dem TLS-Modul eine Anfrage an einen Host senden und das Zertifikat als Objekt abrufen:
In diesem Code extrahiert die Methode getPeerCertificate das Zertifikat. Mit der Methode getPeerX509Certificate können wir das Peer-Zertifikat auch als Objekt im Format x509Certificate abrufen.
SSL/TLS-Pinning in Node.js implementieren
Um SSL/TLS-Pinning in einer Node.js-Anwendung zu verwenden, müssen Sie den Schlüssel oder das Zertifikat in den Anfrageoptionen angeben. Bei HTTPS unterstützen die Eigenschaften ca, cert und key in den Optionen von https.request das SSL/TLS-Pinning. Beim Pinning eines Zertifikats sollte die Eigenschaft `ca` ein Array mit vertrauenswürdigen, im Privacy-Enhanced-Mail-Format (PEM) codierten Zertifikaten oder CA-Zertifikaten enthalten. Die Eigenschaft `key` sollte ein Array mit privaten Schlüsseln enthalten, die zu einem vertrauenswürdigen Serverzertifikat gehören.
Snyk Code ist ein statisches Testtool für Anwendungssicherheit (SAST), das Sicherheitslücken in einer Codebasis während der Entwicklung in Echtzeit erkennt. Es ist über Befehle für die Befehlszeile (CLI), Software Development Kits (SDKs) für CI/CD-Pipelines, Weboberflächen, Erweiterungen für integrierte Entwicklungsumgebungen (IDEs) und Code-Editoren verfügbar. In einem Node.js-Projekt kann Snyk Code fehlende Unterstützung für SSL/TLS-Zertifikate erkennen und Sie darauf hinweisen.
Um fehlende SSL/TLS-Unterstützung zu erkennen, verwenden Sie den folgenden Befehl code test, um die Codebasis des Projekts über Ihr Terminal zu scannen. Mit dem Befehl snyk ignore --file-path=<file_path> können Sie Dateien oder Verzeichnisse vom Snyk-Scan ausschließen, beispielsweise das Verzeichnis node_modules mit den Node.js-Paketen:
SSL/TLS-Pinning bietet zwar Sicherheitsvorteile, kann bei mangelhafter Implementierung ohne Fehlerbehandlung aber auch verheerende Folgen haben. Ihre Pinning-Implementierung sollte einen Fail-Safe-Plan für Sonderfälle vorsehen, etwa wenn ein gepinntes Zertifikat widerrufen wird oder abläuft. Durch Fehlerbehandlung stürzt nicht die gesamte Anwendung ab, wenn ein Zertifikat oder öffentlicher Schlüssel nicht bestätigt werden kann. Audits können dabei helfen, solche Fälle zu protokollieren.
Erstellen Sie zunächst ein Verzeichnis namens snyk-tls und verwenden Sie:
Der folgende Code zeigt einen gepinnten Fingerabdruck des öffentlichen Schlüssels in einer Node.js-Anwendung. Dieser stimmt mit dem Fingerabdruck des öffentlichen Zertifikatsschlüssels für eine GET-Anfrage überein, die mit dem nativen Node.js-Modul https erstellt wurde. Stimmen die Fingerabdrücke der öffentlichen Schlüssel nicht überein, bricht der Code die Anfrage ab. Erstellen Sie eine Datei index.js und fügen Sie den folgenden Code ein, um es auszuprobieren:
Im obigen Code wird das Array PINNED_CERT_FINGERPRINTS geprüft, um festzustellen, ob der Fingerabdruck des öffentlichen Zertifikats zu den zulässigen Fingerabdrücken gehört. Ist er nicht enthalten, bricht die Methode destroy die Anfrage ab.
In der Produktionsumgebung sollten Sie den öffentlichen Schlüssel oder das Zertifikat in Umgebungsvariablen oder einem separaten Key-Vault-Service speichern. So verhindern Sie, dass der öffentliche Schlüssel offengelegt wird, wenn Sie den Code in ein Code-Repository übertragen.
SSL/TLS-Pinning testen und warten
Eine gute Möglichkeit, die Wirksamkeit einer Pinning-Implementierung zu testen, ist die Simulation eines MITM-Angriffs. Mit Tools wie Mitmproxy oder Wireshack können Sie eine Testumgebung einrichten, um Netzwerkanfragen für einen Test-Host zu überwachen, abzufangen und über einen Proxy weiterzuleiten.
Um die Wirksamkeit Ihres SSL/TLS-Pinnings zu testen, deaktivieren Sie die gepinnten Zertifikate und starten Sie über einen Proxy einen MITM-Angriff. So können Sie das Basisverhalten der Anwendung ohne Pinning aufzeichnen. Wiederholen Sie den Test anschließend mit aktiviertem Pinning, um festzustellen, ob die Anwendung den Proxy erkennt und die Verbindung beendet.
Eine weitere Möglichkeit, SSL/TLS-Pinning zu testen, ist der Vergleich des Zertifikatsschlüssel-Hashes. Ein Zertifikat-Hash ist für jedes Zertifikat eindeutig, da eine kryptografische Hashfunktion Daten beliebiger Größe in Werte fester Länge umwandelt, die das Zertifikat repräsentieren. Damit eignet er sich zur Validierung eines Zertifikats. Mit dem Node.js-Modul crypto können Sie einen Hash des Host-Zertifikats erzeugen und mit dem erwarteten Hash des öffentlichen Schlüssels vergleichen.
Eine dritte Möglichkeit, SSL/TLS-Pinning zu testen, ist ein SSL-Portscan mit Netzwerkscanning-Tools wie Nmap. Nmap stellt den Befehl ssl-enum-chipers bereit, um einen SSL-Port auf einem angegebenen Ziel zu scannen.
Gepinnte Zertifikate oder öffentliche Schlüssel zu pflegen und zu aktualisieren, ist entscheidend für das Vertrauen, die Sicherheit und die Integrität der Kommunikationskanäle. Durch regelmäßige Aktualisierungen können Sie die Risiken im Zusammenhang mit kompromittierten, abgelaufenen oder widerrufenen Zertifikaten verringern und zugleich sichere, authentifizierte Verbindungen gewährleisten.
Öffnen Sie den Ordner snyk-tls im Terminal und führen Sie den folgenden Befehl aus.
Dieser Befehl erzeugt eine Datei cert.pem, die das öffentliche Zertifikat für google.com enthält.
Erstellen Sie anschließend im Projektordner eine Datei main.js. Fügen Sie den folgenden Code ein.
Der obige Code importiert die erforderlichen Module und definiert zwei Variablen – certPath und command. certPath gibt den Pfad zur Zertifikatsdatei an. command enthält den Wert des Shell-Befehls, der den SHA-256-Fingerabdruck des Zertifikats erzeugt.
Die Funktion generate_SHA256_fingerprint() verwendet die Funktion exec, um den openssl-Befehl auszuführen, der den SHA-256-Fingerabdruck des Zertifikats erzeugt. Diese Funktion gibt ein Promise zurück, das mit dem Fingerabdruck aufgelöst wird.
Die Funktion verifyCertificate() definiert ein Optionsobjekt zur Konfiguration der HTTPS-Anfrage. Dieses Objekt legt hostname, port, path und method fest. Außerdem definiert es eine Funktion checkServerIdentity(), die das Serverzertifikat überprüft. Diese Funktion stellt sicher, dass das Zertifikat zum Host gehört, mit dem Sie eine Verbindung herstellen, und prüft, ob der Fingerabdruck mit dem gepinnten Fingerabdruck übereinstimmt.
Führen Sie zum Testen dieses Skripts den Befehl node main.js in Ihrem Terminal aus. Die folgende Ausgabe sollte angezeigt werden.
Um ein gepinntes Zertifikat oder einen Schlüssel zu aktualisieren, öffnen Sie die API-Datei und führen den Befehl openssl aus, der die Datei cert.pem erzeugt. Wenn Sie einen externen Vault-Service zum Speichern gepinnter Zertifikate oder öffentlicher Schlüssel verwenden, können Sie die Werte dort bearbeiten, ohne den Anwendungscode zu ändern. In folgenden Fällen müssen gepinnte Zertifikate möglicherweise aktualisiert werden:
Zertifikate oder öffentliche Schlüssel laufen ab
Datenlecks
Widerruf durch den Aussteller
Compliance-Richtlinien, die Nutzer dazu verpflichten, das Zertifikat nach einer festgelegten Dauer zu erneuern
Fazit
In diesem Artikel haben Sie erfahren, wie Sie SSL/TLS-Pinning in Node.js-Anwendungen implementieren. SSL/TLS-Pinning bietet eine zusätzliche Sicherheitsebene, indem der öffentliche Schlüssel oder das Zertifikat des Servers mit einer lokal gespeicherten Kopie abgeglichen wird. So schützt es Ihre Anwendungen vor MITM-Angriffen und anderen zertifikatsbezogenen Schwachstellen.
Node.js verfügt über integrierte Module wie HTTPS, die Certificate-Pinning unterstützen. Sie können SSL/TLS-Pinning implementieren, indem Sie den öffentlichen Schlüssel während des TLS-Handshakes vergleichen und die Verbindung bei einer Abweichung beenden. Eine angemessene Fehlerbehandlung ist ebenfalls wichtig, damit Sie in Sonderfällen nicht ausgesperrt werden, etwa wenn ein Zertifikat oder öffentlicher Schlüssel abläuft oder vom Aussteller widerrufen wird. Eine bewährte Vorgehensweise ist es, SSL/TLS-Pinning in Ihren Anwendungen durch simulierte Angriffe zu testen, Schlüssel-Hashes zu vergleichen und Zertifikate oder Schlüssel zu aktualisieren, um die Wirksamkeit sicherzustellen. Öffentliche Schlüssel sollten außerdem sicher gespeichert werden.
Mit SSL/TLS-Pinning können Sie die allgemeine Sicherheit Ihrer Node.js-Anwendungen verbessern und so ein zuverlässiges und sicheres Nutzungserlebnis gewährleisten.
Starten Sie mit Capture the Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.



