You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/operations/v2.1.0/hardening-measures.md
+88Lines changed: 88 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,3 +5,91 @@ icon: safe
5
5
6
6
# Defense-in-Depth Hardening Measures
7
7
8
+
For DSF {{release.tag}} we performed a number of IT security hardening measures. The following changes follow security best practices. They reduce risk for non-standard deployments, protect against future code changes that could introduce new attack paths, and align with common security audit expectations.
9
+
10
+
Each entry describes the change and why we consider it not exploitable in the standard DSF deployment model.
11
+
12
+
## Deployment Context
13
+
14
+
The standard DSF deployment uses:
15
+
16
+
-**Apache2 reverse proxy** with `mod_ssl` performing TLS termination and client certificate validation (`SSLVerifyClient require`, DN checks against trusted CA list)
-**Jetty application** on internal port 8080, not directly reachable from outside
19
+
-**Status port** on `127.0.0.1:10000` (localhost only), separate Jetty connector
20
+
-**Configuration** via Docker environment variables / secrets, only admin-writable
21
+
-**PostgreSQL** not exposed to host, only accessible from the application container
22
+
23
+
The assessments below consider this standard deployment. Non-standard deployments (e.g., Jetty directly exposed, no reverse proxy) may have different risk profiles.
24
+
25
+
## Improved XML Transformer Configuration
26
+
27
+
Disabled external entity resolution and enabled secure processing on `TransformerFactory` instances in `ProcessService`, `ThymeleafTemplateServiceImpl`, and `BundleGenerator`. We consider this not exploitable because although external organizations and authorized users can create FHIR resources (e.g., Tasks), the content never reaches the TransformerFactory as raw XML. The data path is: user input is parsed by HAPI FHIR into a Java object model (stripping any XML-level constructs like DOCTYPE/ENTITY declarations), stored as JSONB in PostgreSQL, and then re-serialized to well-formed XML by HAPI's serializer when displayed. The TransformerFactory only pretty-prints HAPI's serialized output, where all text content is properly XML-escaped. `BundleGenerator` is a Maven build-time tool, not a runtime component. Hardening against CWE-611 (XXE).
Added regex validation (`^[a-zA-Z_][a-zA-Z0-9_$]{0,62}$`) for PostgreSQL identifier config parameters used in DDL statements. We consider this not exploitable because these values come exclusively from admin-managed config files and Docker environment variables — an attacker with write access to these already has full system control. Hardening against CWE-89.
Added explicit check that OIDC token and JWKS endpoints use HTTPS. We consider this not exploitable because a compromised OIDC provider can already issue arbitrary tokens directly, making HTTP interception redundant. In the MITM scenario (legitimate provider, network attacker), the provider URL is admin-configured as HTTPS and legitimate providers always return HTTPS endpoints in their discovery documents. In both cases, obtained tokens are constrained by the admin-managed `roleConfig` — no privilege escalation beyond configured roles is possible. Hardening against CWE-918 / CWE-319.
Added 2048-bit minimum RSA key length and `use=sig` check for JWKS keys used in JWT verification. We consider this not exploitable because no mainstream OIDC provider (Keycloak, etc.) publishes RSA keys below 2048 bits. Even if an attacker could forge tokens via weak keys, privileges are constrained by the admin-managed `roleConfig` — the same limitation as with a compromised OIDC provider. Hardening against CWE-326 / CWE-347.
Removed DEBUG-level logging of token claims (groups, roles) in `AbstractIdentityProvider` and `BearerTokenAuthenticator`. We consider this not exploitable because DEBUG logging is disabled in production by default, and the logged data (group memberships, roles) is operational metadata — not secrets like passwords or signing keys. Hardening against CWE-532.
Added `Secure`, `HttpOnly`, and `SameSite=LAX` flags to session cookies. We consider this not exploitable because TLS is terminated at the Apache HTTP Server reverse proxy (clients only communicate over HTTPS), the `HttpOnly` flag is only relevant if an XSS vulnerability exists (none is exploitable, see `th:utext` below), and `SameSite` has limited impact since primary authentication uses mTLS, not cookies. Hardening against CWE-614 / CWE-1004.
Replaced string concatenation with Jackson `ObjectMapper` serialization for JSONB query parameters in all DAO classes and search filters. We consider this not exploitable because user-controlled values are bound via `PreparedStatement.setString()`, which transmits query template and parameter values separately to PostgreSQL — the parameter value is never parsed as SQL and there is no way to inject `JOIN`, `UNION`, or subqueries. Within the JSONB domain, the identity filter (access control) operates as a separate `AND` condition with server-side parameters that cannot be influenced by search parameter manipulation, the `@>` containment operator becomes more restrictive with additional injected elements (not less), and result sets are always a subset of authorized resources — no enumeration of unauthorized data is possible. Hardening against CWE-89.
Added explicit certificate expiration check and changed auth type from `"RSA"` to `"UNKNOWN"` in `ClientCertificateAuthenticator`. We consider this not exploitable because the Apache HTTP Server reverse proxy performs TLS termination with `SSLVerifyClient require` and validates certificate expiration, chain trust, and revocation before requests reach Jetty. The Jetty-level check is a redundant second validation. Hardening against CWE-295 / CWE-324.
Replaced `new Yaml()` with `new Yaml(new SafeConstructor(new LoaderOptions()))` in `RoleConfigReader`. We consider this not exploitable because the YAML content comes exclusively from admin-managed config files (`config.properties`) and Docker environment variables — an attacker with write access to these can already execute arbitrary code through simpler means. Hardening against CWE-502.
Replaced `th:utext` (unescaped HTML output) with `th:text` / `th:each` for page headings built from URL segments. We consider this not exploitable because the old code applied `HtmlUtils.htmlEscape()` to all user inputs before concatenation — this escapes `& < > " '`, preventing tag injection (`<``>` escaped to `<``>`) and attribute breakout (`"` escaped to `"`, which per HTML spec does not terminate double-quoted attributes). The fix makes XSS structurally impossible and removes reliance on manual escaping — a future developer could have forgotten the `htmlEscape()` call when adding new URL segments. Hardening against CWE-79.
Removed database exception messages from the status endpoint error response body. We consider this not exploitable because the status endpoint runs on a separate Jetty connector (port 10000, bound to `127.0.0.1` only) with role-based access control (`STATUS_PORT_ROLE`) — it is not reachable through the Apache HTTP Server reverse proxy or from outside the Docker container. Hardening against CWE-209.
## Content Security Policy and Binary Inline Display
92
+
93
+
Introduced a new inline display mode for `Binary` resources with a strict CSP (`script-src 'none'`), a media type policy, and `ContentTypeSanitizer`. We consider this not a vulnerability fix because the old code served all `Binary` resources with `Content-Disposition: attachment` (forced download, never rendered in browser), so the old `unsafe-inline` CSP was never reachable. This commit implements a new feature with secure defaults. Hardening against CWE-1021.
## [Release Notes for v2.0.2](https://github.com/datasharingframework/dsf/releases/tag/v2.0.2)
7
-
8
-
::: tip Release Notes
9
-
You can access all release notes on our [GitHub](https://github.com/datasharingframework/dsf/releases).
10
-
:::
11
-
12
-
### 2.0.2 - Maintenance Release
13
-
General remarks:
14
-
15
-
- This is an update for DSF 2.0.0 / 2.0.1.
16
-
- To Update from an existing 1.x installation, please see the [1.x -> 2.0.2 Upgrade Guide](https://dsf.dev/operations/v2.0.2/upgrade-from-1.html).
17
-
- To Update from an existing 2.x installation, please see the [2.x -> 2.0.2 Upgrade Guide](https://dsf.dev/operations/v2.0.2/upgrade-from-2.html).
18
-
- For a fresh deployment, follow the [installation instructions](https://dsf.dev/operations/v2.0.2/install.html).
19
-
- With this release a number of bugs were fixed.
20
-
21
-
Bug Fixes:
22
-
- The property key `dev.dsf.bpe.fhir.client.connections.config.default.enable.debug.logging` was used for unrelated configuration values to specify the default EnableDebugLogging value for FHIR client connections and the default OidcVerifyAuthorizedParty value for OIDC Client-Credentials-Flow connections. A new property key `dev.dsf.bpe.fhir.client.connections.config.default.oidc.verify.authorized.party` was added.
23
-
- A NoClassDefFoundError was throw when executing the [num-process-dashboard-report](https://github.com/medizininformatik-initiative/dsf-plugin-numdashboard) process plugin in Version 1.0.0.0 and 1.1.0.0. Additional packages were added to the API v1 class allow list file.
24
-
- A process instance waiting for a timer event crashed on continuation if the process plugin was removed. The crash resulted in Task resources remaining in status `in-progress`. Additional error handling was implemented to update Task to a status `failed`.
25
-
- No debug log output was generated for code from the [mii-processes-common](https://github.com/medizininformatik-initiative/mii-processes-common) module used in some medical informatics initiative process plugins. A new config property `dev.dsf.log.min.level.loggers` with default value was added to restore the DSF 1.x behavior.
26
-
- The API v2 `setJsonVariable()` mechanism was unable to serialize date/time objects from the `java.time` package. The `ObjectMapper` configuration was fixed and the `JavaTimeModule` added.
27
-
28
-
Docker images for this release can be accessed via the GitHub Docker registry - ghcr.io:
- NoClassDefFoundError While Executing Plugin num-process-dashboard-report [#415](https://github.com/datasharingframework/dsf/issues/415)
67
-
- Start New Development Cycle [#412](https://github.com/datasharingframework/dsf/issues/412)
68
-
- Property dev.dsf.bpe.fhir.client.connections.config.default.enable.debug.logging Used for Unrelated Configuration Values [#411](https://github.com/datasharingframework/dsf/issues/411)
69
-
70
-
This release contains contributions from [@EmteZogaf](https://github.com/EmteZogaf), [@hhund](https://github.com/hhund), [@jaboehri](https://github.com/jaboehri), [@schwzr](https://github.com/schwzr) and [@wetret](https://github.com/wetret).
0 commit comments