From 8c516c424055ca70f058784b0b8d7e974669f72a Mon Sep 17 00:00:00 2001 From: Marco Holz <marco.holz@fitko.de> Date: Thu, 21 Oct 2021 16:46:11 +0000 Subject: [PATCH] =?UTF-8?q?=C3=9Cberarbeitung=20"Verschl=C3=BCsselte=20?= =?UTF-8?q?=C3=9Cbertragung=20von=20Antragsdaten"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://git.fitko.de/fit-connect/planning/-/issues/113 --- docs/getting-started/encryption.mdx | 96 +++++++++++++++++++---- docs/getting-started/sending/encrypt.mdx | 3 +- static/images/encryption/Briefkasten.png | Bin 0 -> 8858 bytes 3 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 static/images/encryption/Briefkasten.png diff --git a/docs/getting-started/encryption.mdx b/docs/getting-started/encryption.mdx index dcea24602..5c2f8008d 100644 --- a/docs/getting-started/encryption.mdx +++ b/docs/getting-started/encryption.mdx @@ -1,28 +1,92 @@ -# Verschlüsselte Übertragung - import useBaseUrl from '@docusaurus/useBaseUrl'; -FIT-Connect verwendet zur Übertragung von Antragsdaten und Antragsmetadaten, abgesehen von den für die Übermittlung zwingend notwendigen Daten, eine Ende-zu-Ende-Verschlüsselung. -Diese ist auf Basis der Standards [JSON Web Encryption (JWE)](https://tools.ietf.org/html/rfc7516) und [JSON Web Keys (JWK)](https://tools.ietf.org/html/rfc7517) umgesetzt. Bei der Implementierung der Ende-zu-Ende-Verschlüsselung MÜSSEN die [Vorgaben für kryptographische Verfahren](details/crypto.md) beachtet werden. +# Verschlüsselte Übertragung von Antragsdaten -## Warum ist Ende-zu-Ende-Verschlüsselung wichtig? -Im Kontext von Anträgen an Behörden werden häufig höchstsensible Daten übermittelt, die im Rahmen von [Vorgaben des BSI](https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR03107/TR-03107-1.pdf?__blob=publicationFile&v=4) nur Ende-zu-Ende-verschlüsselt übertragen werden dürfen. -Zielsetzung von FIT-Connect ist ein möglichst einfaches, sicheres und klar definiertes Vorgehen zur Einreichung von Antragsdaten zu etablieren. Deshalb ist die verschlüsselte Übertragung von Antragsdaten ein integraler Bestandteil von FIT-Connect. Eine Übertragung von Antragsdaten erfolgt mit FIT-Connect ausschließlich verschlüsselt. +Ziel von FIT-Connect ist es, ein möglichst einfaches, sicheres und klar definiertes Vorgehen zur Einreichung von Antragsdaten zu etablieren. +Deshalb erfolgt eine Übertragung von Antragsdaten mit FIT-Connect ausschließlich verschlüsselt. -## Grundlagen zur sicheren Implementierung von FIT-Connect -### Ende-zu-Ende-Verschlüsselung -FIT-Connect verfolgt den Ansatz einer Ende-zu-Ende-Verschlüsselung. Das bedeutet, dass Daten immer vom Endgerät der Nutzer:in bis in die Zielbehörde bzw. das Fachverfahren asymmetrisch verschlüsselt sind. +## Warum ist Ende-zu-Ende-Verschlüsselung wichtig? +Im Kontext von Anträgen an Behörden werden häufig höchstsensible personenbezogene Daten übermittelt. +Auf grund ihres hohen Schutzbedarfs dürfen solche Daten nach den [Vorgaben des BSI](https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR03107/TR-03107-1.pdf?__blob=publicationFile&v=4) nur Ende-zu-Ende-verschlüsselt übertragen werden. <img src={useBaseUrl('/images/encryption/tls-no-tls.png')} alt="Grafik zur Veranschaulichung einer Ende-zu-Ende-Verschlüsselung" width="600" /> -Zur Realisierung einer Ende-zu-Ende-Verschlüsselung vom Endgerät der Anwender:in bis zum Fachverfahren einer Behörde, dürfen Daten nicht unverschlüsselt oder nur per TLS gesichert an ein Backend übermittelt und erst dort die für FIT-Connect spezifizierte Verschlüsselung angewendet werden. Sollte eine längerfristige Speicherung der Antragsdaten nötig sein, so muss diese immer clientseitig (z.B. in der IndexDB des Browsers, per Download, …) erfolgen. +FIT-Connect verwendet zur Absicherung der Übertragung von Antragsdaten und Antragsmetadaten eine auf asymmetrischer Kryptographie basierenden Ende-zu-Ende-Verschlüsselung. +Abgesehen von denen für die Übermittlung zwingend notwendigen Daten können so nur die Zielbehörde bzw. das Ziel-Fachverfahren die Antragsdaten und Antragsmetadaten entschlüsseln und lesen. +Bei der Umsetzung einer Ende-zu-Ende-Verschlüsselung zwischen dem Endgerät der Nutzer:in und der zuständigen Fachbehörde verlassen sämtliche Inhaltsdaten das Endgerät der Nutzer:in immer verschlüsselt. + +## Grundlagen zur eingesetzten Verschlüsselung + +Die Ende-zu-Ende-Verschlüsselung von FIT-Connect wird mithilfe von hybrider Verschlüsselung auf Basis von [JSON Web Encryption (JWE)](https://datatracker.ietf.org/doc/html/rfc7516) umgesetzt. +Dieser Ansatz kombiniert die Vorteile von symmetrischer und asymmetrischer Verschlüsselung. +Im Folgenden sollen die Grundlagen kurz erläutert werden. + +### Symmetrische Verschlüsselung + +Eine Verschlüsselung wird als symmetrisch bezeichnet, wenn für für Ver- und Entschlüsselung derselbe Schlüssel verwendet wird. +Das ist gleichzeitig auch der größte Nachteil der symmetrischen Verschlüsselung. +Für eine sichere Kommunikation muss immer zuerst allen beteiligten Parteien der geheime Verschlüsselungsschlüssel übermittelt werden. +Man spricht hier auch von einem gemeinsamen Geheimnis (*shared secret*). +Kommt dieses abhanden oder wird beim Austausch abgefangen, ist die Sicherheit der Kommunikation nicht mehr gewährleistet. +Jeder, der in Besitz dieses Schlüssels gelangt, ist im Stande, alle mit ihm verschlüsselten Nachrichten zu entschlüsseln und damit lesen zu können. +Dem gegenüber steht der große Vorteil, dass es mit symmetrischer Verschlüsselung schnell und effizient möglich ist, auch große Datenmengen zu verschlüsseln. + +### Asymmetrische Verschlüsselung + +Eine Verschlüsselung wird als asymmetrisch bezeichnet, wenn es für Ver- und Entschlüsselung im Gegensatz zur symmetrischer Verschlüsselung jeweils einen eigenen Schlüssel gibt. +Die beiden Schlüssel bilden zusammen ein Schlüsselpaar, bestehend aus einem öffentlichen Schlüssel (*public key*) und einem geheimzuhaltenden privaten Schlüssel (*private key*, auch *secret key*). +Der große Vorteil dieses Verfahrens besteht darin, dass für eine sichere Kommunikation den sendenen Parteien nur der öffentliche Schlüssel ausgehändigt werden muss. +Lediglich die zum öffentlichen Schlüssel passenden privaten Schlüssel, mit denen empfangende Nachrichten wieder entschlüsselt werden können, müssen die Nachrichten-Empfänger geheim halten. +Der öffentliche Schlüssel baut bildlich gesprochen einen Schutzcontainer um die Nachricht auf, die nur der zugehörige Empfänger öffnen kann, wie z. B. bei einem Briefkasten, der auch nur vom Besitzer des passenden Briefkastenschlüssels geöffnet werden kann. + +<img src={useBaseUrl('/images/encryption/Briefkasten.png')} alt="Beziehung öffentlicher und privater Schlüssel" width="600" /> + +Im Vergleich zur symmetrischen Verschlüsselung sind die Schlüssel hier jedoch um ein vielfaches länger und die Ver- und Entschlüsselung von Nachrichten erfordert mehr Rechenleistung. +Aus diesem Grund werden die beiden Verfahren bei der Ende-zu-Ende-Verschlüsselung von FIT-Connect kombiniert (sog. *hybride Verschlüsselung*). -### Zertifikate von Zustellpunkten müssen der Verwaltungs-PKI entstammen -Jeder verwendete Public Key (idR. in Form eines JSON Web Keys) muss einem digitalen Zertifikat entstammen und von einer Zertifizierungsstelle innerhalb der Verwaltungs-PKI signiert werden. JSON Web Keys müssen immer mit der komplette Zertifikatskette bis zum Wurzelzertifikat ausgeliefert werden, um clientseitig korrekt validierbar zu sein. +### Hybride Verschlüsselung -### Kryptografisches Material muss vor der Verwendung immer geprüft werden -Die für die Verschlüsselung verwendeten JSON Web Keys müssen vor Verwendung anhand des zugehörigen Zertifikats aus der Verwaltungs-PKI auf Gültigkeit überprüft werden. +Kombiniert man die Vorteile von symmetrischer und asymmetrischer Verschlüsselung in einem gemeinsamen Verfahren, spricht man von einem hybriden Verschlüsselungsverfahren. +Mithilfe von asymmetrischer Verschlüsselung, d. h. dem öffentlichen Schlüssel des Empfängers, verschlüsselt man dabei den symmetrischen Verschlüsselungsschlüssel und kann diesen verschlüsselten Schlüssel dann auch auf einem ungesicherten Kanal übertragen. +Der symmetrische Verschlüsselungsschlüssel kann jetzt in Folge für die eigentliche Inhaltsverschlüsselung genutzt werden, welche dank symmetrischer Verfahren schnell und effizient verschlüsseln kann. + +## Sichere Implementierung der Ende-zu-Ende-Verschlüsselung mit FIT-Connect +Die folgenden Abschnitte geben wichtige grundlegende Hinweise zur sicheren Implementierung der Ende-zu-Ende-Verschlüsselung mit FIT-Connect. Konkrete Implementierungsbeispiele finden sich darüber hinaus in den Artikeln zur [Verschlüsselung](sending/encrypt.mdx) und [Entschlüsselung](receiving/decrypt.mdx) von Antragsdaten. Vorgaben zu zulässigen kryptographischen Algorithmen und Schlüssellängen finden sich im Artikel [Vorgaben für kryptographische Verfahren](../details/crypto.md). + +### Herkunft und Zugehörigkeit von Schlüsseln prüfen + +Wird einem Sender der öffentliche Schlüssel vom designierten Empfänger der Nachricht im Vorlauf nicht sicher und idealerweise sogar persönlich übermittelt, muss auf anderem Weg der oder die Eigentümerin eines Schlüssels ermittelt werden. +Nur so kann man sicher gehen, auch den richtigen Schlüssel zu verwenden. + +Für genau diesen Fall wurden digitale Zertifikate entwickelt. +Digitale Zertifikate sind nichts weiter als öffentliche Schlüssel, angereichert mit beglaubigten Informationen zu seiner Herkunft und dem Eigentümer. +Diese Beglaubigung von Schlüssel und Metainformationen erfolgt durch eine vertrauenswürdige dritte Person oder Institution - üblicherweise einer so genannten Zertifizierungstelle (CA - Certificate Authority) - mithilfe seiner digitalen, für Dritte prüfbaren Unterschrift. + +Ein so ausgestelltes Zertifikat kann dann vom Empfänger wie eine Visitenkarte vor Beginn der verschlüsselten Kommunikation verteilt werden, da es nur öffentliche und auch prüfbare Informationen enthält. + +Die für die Verschlüsselung verwendeten öffentlichen Schlüssel lassen sich so vor Verwendung anhand des zugehörigen Zertifikats aus der Verwaltungs-PKI auf Gültigkeit überprüfen. +Im Artikel [Überprüfen öffentlicher Schlüssel](sending/encrypt.mdx#certificateValidation) werden die zur Prüfung notwendigen Schritte näher erläutert. +Behörden, die zum Empfang von Anträgen berechtigt sind, können sich, wie im Artikel [Zertifikatsbeantragung](receiving/certificate.mdx) beschrieben, Zertifikate aus der Verwaltungs-PKI ausstellen lassen. Für sendende Systeme ist derzeit keine Zertifikatsbeantragung notwendig. <img src={useBaseUrl('/images/encryption/pki-check.png')} alt="Grafik zur Veranschaulichung der Einbindung einer PKI zur Verhinderung von Man-in-the-Middle-Angriffen" width="600" /> -Nicht vertrauenswürdige Schlüssel dürfen nicht für die Verschlüsselung von Anträgen verwendet werden. Das soll Angriffe wie Man-in-the-middle-Attacken verhindern. +Nicht vertrauenswürdige Schlüssel werden abgelehnt und dürfen nicht für die Verschlüsselung von Anträgen verwendet werden. +Die Prüfung von Zertifikaten ist zwingend erforderlich, da sonst Angriffe wie [Man-in-the-middle-Attacken](https://de.wikipedia.org/wiki/Man-in-the-Middle-Angriff) möglich sind. + +### JSON Web Encryption und JWE Compact Serialization + +Die vorangegangen Grundlagen zur Verschlüsselung, hybriden Verfahren und Zertifikaten finden in FIT-Connect in Form von [JSON Web Encryption (JWE)](https://datatracker.ietf.org/doc/html/rfc7516) bei der Verschlüsselung von Antragsdaten (Submissions) Anwendung. +JWE standardisiert die einheitliche Anwendung von kryptographischen Algorithmen und die Repräsentation der dabei genutzten Datenstrukturen. +Dazu nutzt FIT-Connect die [JWE Compact Serialization](https://datatracker.ietf.org/doc/html/rfc7516#section-3.1). +Die Daten innerhalb eines JWE werden möglichst sparsam kodiert und als eine kompakte, URL-sichere Zeichenkette (String) dargestellt. +Der String besteht dabei aus fünf konkatenierten, durch Punkte (.) voneinander getrennten, BASE64URL kodierten Elementen: + + - `JOSE Header` - beschreibt mit welchen asymmetrischen Verfahren der symmetrische Schlüssel zur Inhaltsverschlüsselung verschlüsselt wurde und mit welchem symmetrischen Verfahren die Inhaltsdaten (Ciphertext) verschlüsselt wurden + - `JWE Encrypted Key` - asymmetrisch verschlüsselter, symmetrischer Schlüssel zur Inhaltsverschlüsselung + - `JWE initialization vector` - zufällig ausgewürfelter Initialisierungsvektor, der als Input für die symmetrische Verschlüsselung benötigt wird + - `JWE Ciphertext` - mit dem symmetrischen Schlüssel zur Inhaltsverschlüsselung verschlüsselte Inhaltsdaten + - `JWE Authentication Tag`- bei der Verschlüsselung der Inhaltsdaten zusätzlich ausgegebene Kontrolldaten zur Integritätssicherung + +In unserem Anwendungsfall werden die benötigten öffentlichen Schlüssel der Empfänger mit ihren herkunftsbestätigenden Zertifikaten im System als [JSON Web Key (JWK)](https://tools.ietf.org/html/rfc7517) hinterlegt und können auf Anfrage über die API von sendenden Clients abgerufen werden. +Wie dieser JWK-Abruf im Detail erfolgt, wie Sie die im JWK enthaltenen Zertifikate prüfen können und wie dann mit Hilfe von JWE Antragsdaten verschlüsselt werden, wird im Artikel [Verschlüsseln](sending/encrypt.mdx) beschrieben. +Die Entschlüsselung von Antragsdaten wird im Artikel [Entschlüsseln](receiving/decrypt.mdx) beschrieben. diff --git a/docs/getting-started/sending/encrypt.mdx b/docs/getting-started/sending/encrypt.mdx index 30b459a3a..2746e3e62 100644 --- a/docs/getting-started/sending/encrypt.mdx +++ b/docs/getting-started/sending/encrypt.mdx @@ -45,8 +45,7 @@ Die so verschlüsselten Daten können ausschließlich von diesem Zustellpunkt ge Bevor wir mit der Verschlüsselung loslegen können müssen wir den eben abgerufenen JWK noch auf Gültigkeit überprüfen. -## Überprüfen des öffentlichen Schlüssel (Zertifikatsprüfung) - +## Überprüfen des öffentlichen Schlüssels (Zertifikatsprüfung) {#certificateValidation} :::note Hinweis In der Testumgebung ist die Absicherung der öffentlichen Schlüssel eines Zustellpunktes durch Zertifikate optional. Eine Prüfung der Zertifikate kann in diesem Fall zu Testzwecken entfallen. diff --git a/static/images/encryption/Briefkasten.png b/static/images/encryption/Briefkasten.png new file mode 100644 index 0000000000000000000000000000000000000000..fd8c66e022b122dc8ec03875ae27f1c80be88045 GIT binary patch literal 8858 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 literal 0 HcmV?d00001 -- GitLab