diff options
author | BlackDex <[email protected]> | 2023-10-09 19:17:11 +0200 |
---|---|---|
committer | BlackDex <[email protected]> | 2023-10-09 20:11:20 +0200 |
commit | f3a1385aee241dcbf6a513d5926eae4cd7872e88 (patch) | |
tree | 6f3f2ad2d5e1458d971ed9f6084f4096960da1c9 /src/util.rs | |
parent | 008a2cf298a5c367568957c9290fd88bee9b44af (diff) | |
download | vaultwarden-f3a1385aee241dcbf6a513d5926eae4cd7872e88.tar.gz vaultwarden-f3a1385aee241dcbf6a513d5926eae4cd7872e88.zip |
Do not send extra headers for Upgrade connection
During a WebSocket connection we currently also send several headers
which could cause issues with some reverse proxy, or with the CloudFlare
tunnel for example. This PR resolves these issues.
Fixes #3881
Diffstat (limited to 'src/util.rs')
-rw-r--r-- | src/util.rs | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/src/util.rs b/src/util.rs index 52f371e4..2aef77b3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -33,24 +33,41 @@ impl Fairing for AppHeaders { } async fn on_response<'r>(&self, req: &'r Request<'_>, res: &mut Response<'r>) { + let req_uri_path = req.uri().path(); + let req_headers = req.headers(); + + // Check if this connection is an Upgrade/WebSocket connection and return early + // We do not want add any extra headers, this could cause issues with reverse proxies or CloudFlare + if req_uri_path.ends_with("notifications/hub") || req_uri_path.ends_with("notifications/anonymous-hub") { + match (req_headers.get_one("connection"), req_headers.get_one("upgrade")) { + (Some(c), Some(u)) + if c.to_lowercase().contains("upgrade") && u.to_lowercase().contains("websocket") => + { + // Remove headers which could cause websocket connection issues + res.remove_header("X-Frame-Options"); + res.remove_header("X-Content-Type-Options"); + return; + } + (_, _) => (), + } + } + res.set_raw_header("Permissions-Policy", "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()"); res.set_raw_header("Referrer-Policy", "same-origin"); res.set_raw_header("X-Content-Type-Options", "nosniff"); // Obsolete in modern browsers, unsafe (XS-Leak), and largely replaced by CSP res.set_raw_header("X-XSS-Protection", "0"); - let req_uri_path = req.uri().path(); - // Do not send the Content-Security-Policy (CSP) Header and X-Frame-Options for the *-connector.html files. // This can cause issues when some MFA requests needs to open a popup or page within the clients like WebAuthn, or Duo. - // This is the same behaviour as upstream Bitwarden. + // This is the same behavior as upstream Bitwarden. if !req_uri_path.ends_with("connector.html") { // # Frame Ancestors: // Chrome Web Store: https://chrome.google.com/webstore/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb // Edge Add-ons: https://microsoftedge.microsoft.com/addons/detail/bitwarden-free-password/jbkfoedolllekgbhcbcoahefnbanhhlh?hl=en-US // Firefox Browser Add-ons: https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/ // # img/child/frame src: - // Have I Been Pwned and Gravator to allow those calls to work. + // Have I Been Pwned to allow those calls to work. // # Connect src: // Leaked Passwords check: api.pwnedpasswords.com // 2FA/MFA Site check: api.2fa.directory @@ -72,7 +89,6 @@ impl Fairing for AppHeaders { {allowed_iframe_ancestors}; \ img-src 'self' data: \ https://haveibeenpwned.com \ - https://www.gravatar.com \ {icon_service_csp}; \ connect-src 'self' \ https://api.pwnedpasswords.com \ @@ -619,7 +635,7 @@ fn upcase_value(value: Value) -> Value { } } -// Inner function to handle some speciale case for the 'ssn' key. +// Inner function to handle a special case for the 'ssn' key. // This key is part of the Identity Cipher (Social Security Number) fn _process_key(key: &str) -> String { match key.to_lowercase().as_ref() { |