Zum Hauptinhalt springen

Datensicherheit

Dr.wait verwendet drei Prinzipien, um einen klaren Umgang mit Daten im digitalen Wartezimmer zu ermöglichen. Zusätzlich zur Datensparsamkeit, Datenkurzlebigkeit und Transparenz, schafft Dr.wait eine zusätzliche Ebene an Sicherheit mit einer Ende-zu-Ende-Verschlüsselung der persönlichen Daten. So funktioniert die Verschlüsselung im Detail:

Asymmetrische Verschlüsselung

Ein asymmetrisches Verschlüsselungsverfahren bedeutet im Wesentlichen, dass mit zwei Schlüsseln gearbeitet wird: Ein öffentlicher Schlüssel, um Daten zu verschlüsseln und ein privater Schlüssel, um die verschlüsselten Daten wieder zu entschlüsseln. Ein öffentlicher Schlüssel kann z.B. so aussehen:

-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs0m0fODsKjU/LRzRc1To
WIsxBSfhplEMptf7uSBpUd8Mxtr65Mdtp/Bn1a7M9XoSZ34K0nALFkFSn5T6Vqj3
bpJ2aX3hkk55OhHFo1lFge5hKqwd8PEZUs8aTUuPgZLnMO81MrRV5Msua6/0oRBR
tXlGRauLprewKMneg51kM3U/D4W7Aq8kmLY+n3fJPHwXLOfuKs06Ze7F+WNwBzcT
omDrzpPDhoUMwhvFwDvveS93W0pD7FfudjgNV5olp3q9KWc6OBbPAs2lqja7ZfOo
Hkr93F5sNWMhBJDomGHvQtw72cMgKHXBdLoE31t1J4pWpmWzylTyFcbZuz83YjJs
llf4rETxaRlr9N6EDnF69PLa2KRCiYF9mvUfMXfRQy30GvaP8f+qah5Vdz3H5kxr
2Mwk4NUEdHGbkXwwfpki7kjTy2RvITbj8qsP61v6UMdenGdBLCjzIUI1cCHO2qLs
wA1XI4VbLAXZQTCKiywE6/kcOdS6alyWqUUVz2NKZNQeVafa31zUdKUIKdDAUYEI
luvFyJcoqSpl8gCRz4KbOna9m5HnkUO1ozlJgbMRcwsiBuZnut5O3sECdh54qXve
WLdrPxU20j32ZYOy9gz3iWjO3WN7BEG9X+z8Ec34pbtAaZ1gqd+eRCNZjirZYbwn
7JgdbPRRQIZfevXNujoqGPMCAwEAAQ==
-----END PUBLIC KEY-----

Als Gegenstück zum öffentlichen Schlüssel kann der private Schlüssel so aussehen:

-----BEGIN PRIVATE KEY-----
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
iRX7uDm6DhzzYKu00sMUk7DfEM+32xk=
-----END PRIVATE KEY-----

Das Schlüsselpaar wird nach der erstmaligen Einrichtung auf dem Rechner der Arztpraxis generiert:

const keyPair = await window.crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 4096,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
},
true,
["encrypt", "decrypt"]
)

Key-Wrapping

Um den privaten Schlüssel nicht in Klartext in der Datenbank zu speichern, passiert noch ein wichtiger Schritt: Der private Schlüssel wird mit einem zusätzlichen geheimen Key ummantelt und encodiert. Dieser zusätzlicher Schlüssel wird aus einem - nur der Praxis bekannten - Passwort abgeleitet:

const wrapCryptoKey = async (keyToWrap, password) => {
const salt = window.crypto.getRandomValues(new Uint8Array(16))
const ivWrap = window.crypto.getRandomValues(new Uint8Array(12))
const { iv, wrappingKey } = await getKey(salt, password)

const exportablePrivateKey = await window.crypto.subtle.wrapKey(
"jwk",
keyToWrap,
wrappingKey,
{
name: "AES-GCM",
iv: ivWrap,
}
)

return { exportablePrivateKey, iv, ivWrap, salt }
}
const getKey = async (salt, password) => {
const enc = new TextEncoder()
const keyMaterial = await window.crypto.subtle.importKey(
"raw",
enc.encode(password),
{ name: "PBKDF2" },
false,
["deriveBits", "deriveKey"]
)
const iv = window.crypto.getRandomValues(new Uint8Array(12))

const key = await window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: salt,
iterations: 100000,
hash: "SHA-256",
},
keyMaterial,
{
name: "AES-GCM",
iv: iv,
length: 256,
},
true,
["wrapKey", "unwrapKey"]
)
return { wrappingKey: key, iv, salt }
}

Der private Schlüssel, ummantelt mit dem Passwort, wird nun für die Praxis in der Datenbank gespeichert und kann von allen Praxismitarbeitern aufgerufen werden.

Wie werden die Daten jetzt verschlüsselt?

Zurück zu den Daten. Bei Dr.wait werden die Patientendaten also mit dem öffentlichen Schüssel der Praxis bereits auf dem Smartphone in der Patienten-App verschlüsselt. Das sieht ungefähr so aus:

const encryptData = async (str, publicKey) => {
let enc = new TextEncoder()
const encoded = enc.encode(str)
const encrypted = await window.crypto.subtle.encrypt(
{
name: "RSA-OAEP",
hash: "SHA-256",
},
publicKey,
encoded
)

return btoa(String.fromCharCode(...new Uint8Array(encrypted)))
}

const publicKey = "-----BEGIN PUBLIC KEY-----..." // See above for full public key.
const encryptedName = encryptData("Joe Duncan", publicKey)

Nach dem erfolgreichen Verschlüsseln werden die Patientendaten aus der App zu den Servern von Dr.wait geschickt und in der Datenbank gespeichert.

Auf den Computern der Praxis werden nach erfolgreicher Authentifizierung der Praxismitarbeiter, die gesamte Warteschlange samt verschlüsselter Daten geladen. Um die Daten zu entschlüsseln, wird der private Schlüssel (mit einem Passwort ummantelt) aus der Datenbank geladen und nach Eingabe des Passworts durch die Praxis dekodiert.

Die Ebenen der Sicherheit

Das asymmetrische Verschlüsselungsverfahren schafft im Zusammenspiel mit Key-Wrapping eine gute zusätzliche Ebene an Datensicherheit. Das hilft natürlich auch nur, wenn die Sicherheit in anderen Bereichen wie Datenbankzugriff, Serververwaltung und Datenübertragung auch beachtet wird.