Skip to main content

rust_webx_host/
security_headers.rs

1//! Security headers middleware for the rust-webx framework.
2//!
3//! Adds recommended security-related HTTP response headers to every response.
4
5use rust_webx_core::error::Result;
6use rust_webx_core::http::IHttpContext;
7use rust_webx_core::middleware::IMiddleware;
8use std::ops::ControlFlow;
9
10/// Middleware that adds a standard set of security headers to every response.
11pub struct SecurityHeadersMiddleware;
12
13impl SecurityHeadersMiddleware {
14    /// Create a new security headers middleware.
15    pub fn new() -> Self {
16        Self
17    }
18}
19
20impl Default for SecurityHeadersMiddleware {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26#[async_trait::async_trait]
27impl IMiddleware for SecurityHeadersMiddleware {
28    async fn invoke(&self, ctx: &mut dyn IHttpContext) -> Result<ControlFlow<()>> {
29        let resp = ctx.response_mut();
30
31        // Prevent MIME type sniffing
32        resp.set_header("x-content-type-options", "nosniff");
33
34        // Prevent clickjacking
35        resp.set_header("x-frame-options", "DENY");
36
37        // Force HTTPS for 1 year (HSTS)
38        resp.set_header(
39            "strict-transport-security",
40            "max-age=31536000; includeSubDomains",
41        );
42
43        // Referrer policy
44        resp.set_header("referrer-policy", "strict-origin-when-cross-origin");
45
46        // Permissions policy (disable sensitive features)
47        resp.set_header(
48            "permissions-policy",
49            "camera=(), microphone=(), geolocation=()",
50        );
51
52        // `cache-control` is intentionally not set here: the correct default
53        // depends on what the response turns out to be. `finalize_response`
54        // applies `no-store` to ordinary responses and a revalidating policy to
55        // file responses, and never overrides a value the application set.
56
57        Ok(ControlFlow::Continue(()))
58    }
59}