kanidmd_core/https/middleware/security_headers.rs
1use axum::{
2 body::Body,
3 extract::State,
4 http::{header, HeaderValue, Request},
5 middleware::Next,
6 response::Response,
7};
8
9use crate::https::ServerState;
10
11const PERMISSIONS_POLICY_VALUE: &str = "fullscreen=(), geolocation=()";
12const X_CONTENT_TYPE_OPTIONS_VALUE: &str = "nosniff";
13
14pub async fn security_headers_layer(
15 State(state): State<ServerState>,
16 request: Request<Body>,
17 next: Next,
18) -> Response {
19 // wait for the middleware to come back
20 let mut response = next.run(request).await;
21
22 // add the Content-Security-Policy header, which defines how contact will be accessed/run based on the source URL
23 let headers = response.headers_mut();
24 headers.insert(header::CONTENT_SECURITY_POLICY, state.csp_header);
25
26 // X-Content-Type-Options tells the browser if it's OK to "sniff" or guess the content type of a response
27 //
28 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
29 // https://scotthelme.co.uk/hardening-your-http-response-headers/#x-content-type-options
30 headers.insert(
31 header::X_CONTENT_TYPE_OPTIONS,
32 HeaderValue::from_static(X_CONTENT_TYPE_OPTIONS_VALUE),
33 );
34
35 // Permissions policy defines access to platform services like geolocation, fullscreen etc.
36 //
37 // https://www.w3.org/TR/permissions-policy-1/
38 headers.insert(
39 "Permissions-Policy",
40 HeaderValue::from_static(PERMISSIONS_POLICY_VALUE),
41 );
42
43 // Don't send a referrer header when the user is navigating to a non-HTTPS URL
44 // Ref:
45 // https://scotthelme.co.uk/a-new-security-header-referrer-policy/
46 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
47 headers.insert(
48 header::REFERRER_POLICY,
49 HeaderValue::from_static("no-referrer-when-downgrade"),
50 );
51
52 response
53}