http_types/security/
mod.rs

1//! HTTP Security Headers.
2//!
3//! # Specifications
4//!
5//! - [W3C Timing-Allow-Origin header](https://w3c.github.io/resource-timing/#sec-timing-allow-origin)
6//!
7//! # Example
8//!
9//! ```
10//! use http_types::{StatusCode, Response};
11//!
12//! let mut res = Response::new(StatusCode::Ok);
13//! http_types::security::default(&mut res);
14// //! assert_eq!(res["X-Content-Type-Options"], "nosniff");
15// //! assert_eq!(res["X-XSS-Protection"], "1; mode=block");
16//! ```
17
18use crate::headers::{HeaderName, HeaderValue, Headers};
19
20mod csp;
21mod timing_allow_origin;
22
23pub use csp::{ContentSecurityPolicy, ReportTo, ReportToEndpoint, Source};
24#[doc(inline)]
25pub use timing_allow_origin::TimingAllowOrigin;
26
27/// Apply a set of default protections.
28///
29// /// ## Examples
30// /// ```
31// /// use http_types::Response;
32// ///
33// /// let mut res = Response::new(StatusCode::Ok);
34// /// http_types::security::default(&mut headers);
35// /// assert_eq!(headers["X-Content-Type-Options"], "nosniff");
36// /// assert_eq!(headers["X-XSS-Protection"], "1; mode=block");
37// /// ```
38pub fn default(mut headers: impl AsMut<Headers>) {
39    dns_prefetch_control(&mut headers);
40    nosniff(&mut headers);
41    frameguard(&mut headers, None);
42    powered_by(&mut headers, None);
43    hsts(&mut headers);
44    xss_filter(&mut headers);
45}
46
47/// Disable browsers’ DNS prefetching by setting the `X-DNS-Prefetch-Control` header.
48///
49/// [read more](https://helmetjs.github.io/docs/dns-prefetch-control/)
50///
51// /// ## Examples
52// /// ```
53// /// use http_types::Response;
54// ///
55// /// let mut res = Response::new(StatusCode::Ok);
56// /// http_types::security::dns_prefetch_control(&mut headers);
57// /// assert_eq!(headers["X-DNS-Prefetch-Control"], "on");
58// /// ```
59#[inline]
60pub fn dns_prefetch_control(mut headers: impl AsMut<Headers>) {
61    headers.as_mut().insert("X-DNS-Prefetch-Control", "on");
62}
63
64/// Set the frameguard level.
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66pub enum FrameOptions {
67    /// Set to `sameorigin`
68    SameOrigin,
69    /// Set to `deny`
70    Deny,
71}
72
73/// Mitigates clickjacking attacks by setting the `X-Frame-Options` header.
74///
75/// [read more](https://helmetjs.github.io/docs/frameguard/)
76///
77// /// ## Examples
78// /// ```
79// /// use http_types::Response;
80// ///
81// /// let mut res = Response::new(StatusCode::Ok);
82// /// http_types::security::frameguard(&mut headers, None);
83// /// assert_eq!(headers["X-Frame-Options"], "sameorigin");
84// /// ```
85#[inline]
86pub fn frameguard(mut headers: impl AsMut<Headers>, guard: Option<FrameOptions>) {
87    let kind = match guard {
88        None | Some(FrameOptions::SameOrigin) => "sameorigin",
89        Some(FrameOptions::Deny) => "deny",
90    };
91    headers.as_mut().insert("X-Frame-Options", kind);
92}
93
94/// Removes the `X-Powered-By` header to make it slightly harder for attackers to see what
95/// potentially-vulnerable technology powers your site.
96///
97/// [read more](https://helmetjs.github.io/docs/hide-powered-by/)
98///
99// /// ## Examples
100// /// ```
101// /// use http_types::Response;
102// ///
103// /// let mut res = Response::new(StatusCode::Ok);
104// /// headers.as_mut().insert("X-Powered-By", "Tide/Rust".parse());
105// /// http_types::security::hide_powered_by(&mut headers);
106// /// assert_eq!(headers.get("X-Powered-By"), None);
107// /// ```
108#[inline]
109pub fn powered_by(mut headers: impl AsMut<Headers>, value: Option<HeaderValue>) {
110    let name = HeaderName::from_lowercase_str("X-Powered-By");
111    match value {
112        Some(value) => {
113            headers.as_mut().insert(name, value);
114        }
115        None => {
116            headers.as_mut().remove(name);
117        }
118    };
119}
120
121/// Sets the `Strict-Transport-Security` header to keep your users on `HTTPS`.
122///
123/// Note that the header won’t tell users on HTTP to switch to HTTPS, it will tell HTTPS users to
124/// stick around. Defaults to 60 days.
125///
126/// [read more](https://helmetjs.github.io/docs/hsts/)
127///
128// /// ## Examples
129// /// ```
130// /// use http_types::Response;
131// ///
132// /// let mut res = Response::new(StatusCode::Ok);
133// /// http_types::security::hsts(&mut headers);
134// /// assert_eq!(headers["Strict-Transport-Security"], "max-age=5184000");
135// /// ```
136#[inline]
137pub fn hsts(mut headers: impl AsMut<Headers>) {
138    headers
139        .as_mut()
140        .insert("Strict-Transport-Security", "max-age=5184000");
141}
142
143/// Prevent browsers from trying to guess (“sniff”) the MIME type, which can have security
144/// implications.
145///
146/// [read more](https://helmetjs.github.io/docs/dont-sniff-mimetype/)
147///
148// /// ## Examples
149// /// ```
150// /// use http_types::Response;
151// ///
152// /// let mut res = Response::new(StatusCode::Ok);
153// /// http_types::security::nosniff(&mut headers);
154// /// assert_eq!(headers["X-Content-Type-Options"], "nosniff");
155// /// ```
156#[inline]
157pub fn nosniff(mut headers: impl AsMut<Headers>) {
158    headers.as_mut().insert("X-Content-Type-Options", "nosniff");
159}
160
161/// Sets the `X-XSS-Protection` header to prevent reflected XSS attacks.
162///
163/// [read more](https://helmetjs.github.io/docs/xss-filter/)
164///
165// /// ## Examples
166// /// ```
167// /// use http_types::Response;
168// ///
169// /// let mut res = Response::new(StatusCode::Ok);
170// /// http_types::security::xss_filter(&mut headers);
171// /// assert_eq!(headers["X-XSS-Protection"], "1; mode=block");
172// /// ```
173#[inline]
174pub fn xss_filter(mut headers: impl AsMut<Headers>) {
175    headers.as_mut().insert("X-XSS-Protection", "1; mode=block");
176}
177
178/// Set the Referrer-Policy level
179#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
180pub enum ReferrerOptions {
181    /// Set to "no-referrer"
182    NoReferrer,
183    /// Set to "no-referrer-when-downgrade" the default
184    NoReferrerDowngrade,
185    /// Set to "same-origin"
186    SameOrigin,
187    /// Set to "origin"
188    Origin,
189    /// Set to "strict-origin"
190    StrictOrigin,
191    /// Set to "origin-when-cross-origin"
192    CrossOrigin,
193    /// Set to "strict-origin-when-cross-origin"
194    StrictCrossOrigin,
195    /// Set to "unsafe-url"
196    UnsafeUrl,
197}
198
199/// Mitigates referrer leakage by controlling the referer\[sic\] header in links away from pages
200///
201/// [read more](https://scotthelme.co.uk/a-new-security-header-referrer-policy/)
202///
203/// [Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy)
204///
205///
206// /// ## Examples
207// /// ```
208// /// use http_types::Response;
209// ///
210// /// let mut res = Response::new(StatusCode::Ok);
211// /// http_types::security::referrer_policy(&mut headers, Some(http_types::security::ReferrerOptions::UnsafeUrl));
212// /// http_types::security::referrer_policy(&mut headers, None);
213// /// let mut referrerValues: Vec<&str> = headers.get_all("Referrer-Policy").iter().map(|x| x.to_str().unwrap()).collect();
214// /// assert_eq!(referrerValues.sort(), vec!("unsafe-url", "no-referrer").sort());
215// /// ```
216#[inline]
217pub fn referrer_policy(mut headers: impl AsMut<Headers>, referrer: Option<ReferrerOptions>) {
218    let policy = match referrer {
219        None | Some(ReferrerOptions::NoReferrer) => "no-referrer",
220        Some(ReferrerOptions::NoReferrerDowngrade) => "no-referrer-when-downgrade",
221        Some(ReferrerOptions::SameOrigin) => "same-origin",
222        Some(ReferrerOptions::Origin) => "origin",
223        Some(ReferrerOptions::StrictOrigin) => "strict-origin",
224        Some(ReferrerOptions::CrossOrigin) => "origin-when-cross-origin",
225        Some(ReferrerOptions::StrictCrossOrigin) => "strict-origin-when-cross-origin",
226        Some(ReferrerOptions::UnsafeUrl) => "unsafe-url",
227    };
228
229    // We MUST allow for multiple Referrer-Policy headers to be set.
230    // See: https://w3c.github.io/webappsec-referrer-policy/#unknown-policy-values example #13
231    headers.as_mut().append("Referrer-Policy", policy);
232}