From 50352516685622924e3f9810acc5fc4e2237df51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= <33655937+jkoenig134@users.noreply.github.com> Date: Mon, 11 Nov 2024 11:20:46 +0100 Subject: [PATCH] Add TLS Certificate Pinning (#281) * fix: use default shell * feat: add new config options * feat: add certificate pinning to security considerations * chore: PR commetns * fix: do not break the docs * oppercase middle of sentence * chore: PR comments --- .vscode/tasks.json | 1 + _docs_operate/configuration.md | 66 +++++++++++++++++++++++- _docs_operate/security-considerations.md | 9 ++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index c50b09f9c..4eaad492d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -9,6 +9,7 @@ "kind": "test", "isDefault": true }, + "options": { "shell": { "args": [] } }, "isBackground": true }, { diff --git a/_docs_operate/configuration.md b/_docs_operate/configuration.md index 15dd8dbd2..d3dfe164a 100644 --- a/_docs_operate/configuration.md +++ b/_docs_operate/configuration.md @@ -87,6 +87,8 @@ The Connector provides the following configuration parameters: ```jsonc { "debug": false, + "enforceCertificatePinning": false, + "pinnedTLSCertificateSHA256Fingerprints": {}, "transportLibrary": { "baseUrl": "BASE_URL", "platformClientId": "CLIENT_ID", @@ -110,6 +112,68 @@ You can validate the config using our [schema file](https://raw.githubuserconten The debug flag configures if the Connector is set to **production** or **debug** mode. Defaults to `false`. Can also be configured using the environment variable `DEBUG`. +### enforceCertificatePinning `available since version 6.5.0` {#enforceCertificatePinning} + +The `enforceCertificatePinning` flag configures whether the Connector should enforce certificate pinning. Defaults to `false`. + +If enabled, the Connector will only accept TLS certificates that match the SHA256 fingerprints for endpoints of outgoing requests specified in the [`pinnedTLSCertificateSHA256Fingerprints`](#pinnedTLSCertificateSHA256Fingerprints) object. If a hostname is not configured at all, it cannot be accessed by the Connector anymore. + +### pinnedTLSCertificateSHA256Fingerprints `available since version 6.5.0` {#pinnedTLSCertificateSHA256Fingerprints} + +The `pinnedTLSCertificateSHA256Fingerprints` object maps hostnames to TLS certificate SHA256 fingerprints of the respective hostname. If a hostname is found, the Connector only accepts a TLS connection if the server responds with a certificate of one of the given fingerprints. The fingerprints must be in a hexadecimal format and are internally stripped of separators and characters not valid for hexadecimal formats. To reduce attack vectors, wildcard domains like "\*.enmeshed.eu" are not valid hostnames, you need to fill this map with every subdomain. + +To increase security, please consider setting [`enforceCertificatePinning`](#enforceCertificatePinning) to true. + +TLS certificates are rotated multiple times in a year for each hostname. Therefore, setting multiple fingerprints per hostname is possible. However, the config and fingerprints need to be updated regularly with the new fingerprints, otherwise the Connector will reject outgoing requests for expired certificates and cease to function. +{: .notice--warning} + +**Getting the SHA256 fingerprint of a certificate:** + +```bash +echo -n | openssl s_client -connect :443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cert.pem +openssl x509 -noout -in cert.pem -fingerprint -sha256 +rm cert.pem +``` + +This will output something similar to: + +```text +Connecting to +... +DONE +sha256 Fingerprint=AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA +``` + +You can simply copy the fingerprint after `sha256 Fingerprint=` and use it. + +If you use another way to acquire the fingerprint, the Connector understands multiple formats like + +```text +AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +``` + +**Sample Configuration:** + +```jsonc +{ + // ... + + "pinnedTLSCertificateSHA256Fingerprints": { + "example.com": [ + "AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA", + "BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB:BB" + ], + "subdomain.example.com": [ + "AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA", + "CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC:CC" + ] + } +} +``` + ### transportLibrary - **baseUrl** `required` @@ -183,7 +247,7 @@ The HTTP server is the base for the `coreHttpApi` Module. It opens an express HT The API-Key protects your Connector from unauthorized access and should therefore be kept secret. -- **helmetOptions** `default: depending on the connector mode` +- **helmetOptions** `default: depending on the Connector mode` Configure the [helmet](https://helmetjs.github.io/) middleware. diff --git a/_docs_operate/security-considerations.md b/_docs_operate/security-considerations.md index cb7da16a7..153d6faeb 100644 --- a/_docs_operate/security-considerations.md +++ b/_docs_operate/security-considerations.md @@ -79,6 +79,15 @@ The Connector does need to access its database. Access to other networks or syst Depending on the integration setup, access to the Connector from the internal network could be blocked for the majority of requests. Usually, only requests from the integration systems, the developers or administrators need to be allowed. +### TLS Certificate Pinning + +To make the Connector resistant against man-in-the-middle attacks, it is recommended to use [TLS certificate pinning](https://www.ssl.com/blogs/what-is-certificate-pinning/). This means that the Connector only accepts a specific certificate for the connection to the Backbone. This certificate [should be pinned in the Connector configuration]({% link _docs_operate/configuration.md %}#pinnedTLSCertificateSHA256Fingerprints). + +As an additional security mechanism, we recommend to [enforce certificate pinning]({% link _docs_operate/configuration.md %}#enforceCertificatePinning) to make sure that the Connector does not access any other HTTPS domain other than the ones specified in the configuration. + +Certificate pinning adds additional effort to the Connector administrators, as for every hostname and TLS certificate, the fingerprints must be regularly updated over the config. Be aware that the Connector might reject TLS connections and cease to function if this configuration is not maintained.
Be also aware that the Connector might reject TLS connections seemingly at random, if on the server infrastructure, multiple TLS certificates or redirection is used.
As TLS certificates are maintained by the domain owner of the hostname, establishing a communication channel between Connector administrator and TLS server administrator is recommended. +{: .notice--warning} + ## Authentication and User Management So far, the Connector supports API-Key authentication to securely authenticate technical users. These API-Keys are random character strings with a high entropy and should be kept confidential at all times. Each internal system communicating with the Connector should receive its own API-Key.