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