Rocket

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit c5167f1150dd602d0f84e695c5d4fe31b5dff5fc
parent 0ac6c18deb3bbf4055b1e7b9d68178c6c029b12b
Author: Tal <talg@cs.stanford.edu>
Date:   Thu, 30 Aug 2018 15:52:54 -0700

Add 'space_helmet' contrib module.

Diffstat:
MCargo.toml | 1+
Mcontrib/lib/Cargo.toml | 7+++++++
Mcontrib/lib/src/lib.rs | 2++
Acontrib/lib/src/space_helmet/helmet.rs | 285+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/lib/src/space_helmet/mod.rs | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/lib/src/space_helmet/policy.rs | 302++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Acontrib/lib/tests/space_helmet.rs | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/space_helmet/Cargo.toml | 18++++++++++++++++++
Aexamples/space_helmet/Rocket.toml | 4++++
Aexamples/space_helmet/private/cert.pem | 30++++++++++++++++++++++++++++++
Aexamples/space_helmet/private/key.pem | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Aexamples/space_helmet/src/hello.rs | 33+++++++++++++++++++++++++++++++++
Mscripts/test.sh | 1+
13 files changed, 921 insertions(+), 0 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "core/http/", "contrib/lib", "contrib/codegen", + "examples/space_helmet", "examples/cookies", "examples/errors", "examples/form_validation", diff --git a/contrib/lib/Cargo.toml b/contrib/lib/Cargo.toml @@ -21,6 +21,7 @@ json = ["serde", "serde_json"] msgpack = ["serde", "rmp-serde"] tera_templates = ["tera", "templates"] handlebars_templates = ["handlebars", "templates"] +space_helmet = ["time"] serve = [] # The barage of user-facing database features. @@ -66,8 +67,14 @@ r2d2_cypher = { version = "0.4", optional = true } redis = { version = "0.9", optional = true } r2d2_redis = { version = "0.8", optional = true } +# SpaceHelmet dependencies +time = { version = "0.1.40", optional = true } + [target.'cfg(debug_assertions)'.dependencies] notify = { version = "^4.0" } +[dev-dependencies] +rocket_codegen = { version = "0.4.0-dev", path = "../../core/codegen" } + [package.metadata.docs.rs] all-features = true diff --git a/contrib/lib/src/lib.rs b/contrib/lib/src/lib.rs @@ -24,6 +24,7 @@ //! * [tera_templates](templates) - Tera Templating //! * [uuid](uuid) - UUID (de)serialization //! * [${database}_pool](databases) - Database Configuration and Pooling +//! * [space_helmet](space_helmet) //! //! The recommend way to include features from this crate via Cargo in your //! project is by adding a `[dependencies.rocket_contrib]` section to your @@ -49,6 +50,7 @@ #[cfg(feature="templates")] pub mod templates; #[cfg(feature="uuid")] pub mod uuid; #[cfg(feature="databases")] pub mod databases; +#[cfg(feature = "space_helmet")] pub mod space_helmet; #[cfg(feature="databases")] extern crate rocket_contrib_codegen; #[cfg(feature="databases")] #[doc(hidden)] pub use rocket_contrib_codegen::*; diff --git a/contrib/lib/src/space_helmet/helmet.rs b/contrib/lib/src/space_helmet/helmet.rs @@ -0,0 +1,285 @@ +use std::sync::atomic::{AtomicBool, Ordering}; + +use rocket::fairing::{Fairing, Info, Kind}; +use rocket::http::Header; +use rocket::{Request, Response, Rocket}; + +use super::policy::*; + +/// A [`Fairing`](/rocket/fairing/trait.Fairing.html) +/// that adds HTTP headers to outgoing responses that control security features +/// on the browser. +/// +/// # Usage +/// +/// `SpaceHelmet` can be used in several ways. +/// +/// To use it with its [defaults](#method.default), create a new instance and +/// attach it to [Rocket](/rocket/struct.Rocket.html) +/// as shown. +/// +/// ```rust +/// # extern crate rocket; +/// # extern crate rocket_contrib; +/// use rocket_contrib::space_helmet::SpaceHelmet; +/// +/// let rocket = rocket::ignite().attach(SpaceHelmet::default()); +/// ``` +/// +/// To enable an additional header, call the method for that header, with the +/// policy for that header, before attach e.g. +/// +/// ```rust +/// # extern crate rocket; +/// # extern crate rocket_contrib; +/// use rocket_contrib::space_helmet::{SpaceHelmet, ReferrerPolicy}; +/// +/// let helmet = SpaceHelmet::default().referrer_policy(ReferrerPolicy::NoReferrer); +/// let rocket = rocket::ignite().attach(helmet); +/// ``` +/// +/// To disable a header, call the method for that header with `None` as +/// the policy. +/// +/// ```rust +/// # extern crate rocket; +/// # extern crate rocket_contrib; +/// use rocket_contrib::space_helmet::SpaceHelmet; +/// +/// let helmet = SpaceHelmet::default().no_sniff(None); +/// let rocket = rocket::ignite().attach(helmet); +/// ``` +/// +/// `SpaceHelmet` supports the builder pattern to configure multiple policies +/// +/// ```rust +/// # extern crate rocket; +/// # extern crate rocket_contrib; +/// use rocket_contrib::space_helmet::{HstsPolicy, ExpectCtPolicy, ReferrerPolicy, SpaceHelmet}; +/// +/// let helmet = SpaceHelmet::default() +/// .hsts(HstsPolicy::default()) +/// .expect_ct(ExpectCtPolicy::default()) +/// .referrer_policy(ReferrerPolicy::default()); +/// +/// let rocket = rocket::ignite().attach(helmet); +/// ``` +/// +/// # TLS and HSTS +/// +/// If TLS is enabled when a [Rocket](rocket/struct.Rocket.html) +/// is [launched](/rocket/fairing/trait.Fairing.html#method.on_launch) +/// in a non-development environment e.g. [Staging](rocket/struct.Config.html#method.staging) +/// or [Production](/rocket/struct.Config.html#method.production) +/// `SpaceHelmet` enables hsts with its default policy and issue a +/// warning. +/// +/// To get rid of this warning, set an [hsts](#method.hsts) policy if you are using tls. +pub struct SpaceHelmet<'a> { + expect_ct_policy: Option<ExpectCtPolicy<'a>>, + no_sniff_policy: Option<NoSniffPolicy>, + xss_protect_policy: Option<XssPolicy<'a>>, + frameguard_policy: Option<FramePolicy<'a>>, + hsts_policy: Option<HstsPolicy>, + force_hsts_policy: Option<HstsPolicy>, + force_hsts: AtomicBool, + referrer_policy: Option<ReferrerPolicy>, +} + +// helper for Helmet.apply +macro_rules! try_apply_header { + ($self:ident, $response:ident, $policy_name:ident) => { + if let Some(ref policy) = $self.$policy_name { + if $response.set_header(policy) { + warn_!( + "(Space Helmet): set_header failed, found existing header \"{}\"", + Header::from(policy).name + ); + } + } + }; +} + +impl<'a> Default for SpaceHelmet<'a> { + /// Returns a new `SpaceHelmet` instance. See [table](/rocket_contrib/space_helmet/index.html#what-it-supports) for + /// a description of what policies are used by default. + /// + /// # Example + /// + /// ```rust + /// # extern crate rocket; + /// # extern crate rocket_contrib; + /// use rocket_contrib::space_helmet::SpaceHelmet; + /// + /// let helmet = SpaceHelmet::default(); + /// ``` + fn default() -> Self { + Self { + expect_ct_policy: None, + no_sniff_policy: Some(NoSniffPolicy::default()), + frameguard_policy: Some(FramePolicy::default()), + xss_protect_policy: Some(XssPolicy::default()), + hsts_policy: None, + force_hsts_policy: Some(HstsPolicy::default()), + force_hsts: AtomicBool::new(false), + referrer_policy: None, + } + } +} + +impl<'a> SpaceHelmet<'a> { + /// Same as [`SpaceHelmet::default()`]. + pub fn new() -> Self { + SpaceHelmet::default() + } + + /// Sets the [X-XSS-Protection]( + /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection) + /// header to the given `policy` or disables it if `policy == None`. + /// # Example + /// + /// ```rust + /// # extern crate rocket; + /// # extern crate rocket_contrib; + /// use rocket::http::uri::Uri; + /// use rocket_contrib::space_helmet::{SpaceHelmet, XssPolicy}; + /// + /// let report_uri = Uri::parse("https://www.google.com").unwrap(); + /// let helmet = SpaceHelmet::new().xss_protect(XssPolicy::EnableReport(report_uri)); + /// ``` + pub fn xss_protect<T: Into<Option<XssPolicy<'a>>>>(mut self, policy: T) -> SpaceHelmet<'a> { + self.xss_protect_policy = policy.into(); + self + } + + /// Sets the [X-Content-Type-Options]( + /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options) + /// header to `policy` or disables it if `policy == None`. + /// # Example + /// + /// ```rust + /// + /// use rocket_contrib::space_helmet::{SpaceHelmet, NoSniffPolicy}; + /// + /// let helmet = SpaceHelmet::new().no_sniff(NoSniffPolicy::Enable); + /// ``` + pub fn no_sniff<T: Into<Option<NoSniffPolicy>>>(mut self, policy: T) -> SpaceHelmet<'a> { + self.no_sniff_policy = policy.into(); + self + } + + /// Sets the [X-Frame-Options]( + /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) + /// header to `policy`, or disables it if `policy == None`. + /// # Example + /// + /// ```rust + /// # extern crate rocket; + /// # extern crate rocket_contrib; + /// + /// use rocket::http::uri::Uri; + /// use rocket_contrib::space_helmet::{SpaceHelmet, FramePolicy}; + /// + /// let allow_uri = Uri::parse("https://www.google.com").unwrap(); + /// let helmet = SpaceHelmet::new().frameguard(FramePolicy::AllowFrom(allow_uri)); + /// ``` + pub fn frameguard<T: Into<Option<FramePolicy<'a>>>>(mut self, policy: T) -> SpaceHelmet<'a> { + self.frameguard_policy = policy.into(); + self + } + + /// Sets the [Strict-Transport-Security]( + /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security) + /// header to `policy`, or disables it if `policy == None`. + /// # Example + /// + /// ```rust + /// use rocket_contrib::space_helmet::{SpaceHelmet, HstsPolicy}; + /// + /// let helmet = SpaceHelmet::new().hsts(HstsPolicy::default()); + /// ``` + pub fn hsts<T: Into<Option<HstsPolicy>>>(mut self, policy: T) -> SpaceHelmet<'a> { + self.hsts_policy = policy.into(); + self + } + + /// Sets the [Expect-CT]( + /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT) + /// header to `policy`, or disables it if `policy == None`. + /// ```rust + /// # extern crate rocket; + /// # extern crate rocket_contrib; + /// # extern crate time; + /// use rocket::http::uri::Uri; + /// use rocket_contrib::space_helmet::{SpaceHelmet, ExpectCtPolicy}; + /// use time::Duration; + /// + /// let report_uri = Uri::parse("https://www.google.com").unwrap(); + /// let helmet = SpaceHelmet::new() + /// .expect_ct(ExpectCtPolicy::ReportAndEnforce( + /// Duration::days(30), report_uri)); + /// ``` + pub fn expect_ct<T: Into<Option<ExpectCtPolicy<'a>>>>(mut self, policy: T) -> SpaceHelmet<'a> { + self.expect_ct_policy = policy.into(); + self + } + + /// Sets the [Referrer-Policy]( + /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy) + /// header to `policy`, or disables it if `policy == None`. + /// ```rust + /// # extern crate rocket; + /// # extern crate rocket_contrib; + /// + /// use rocket_contrib::space_helmet::{ReferrerPolicy, SpaceHelmet}; + /// + /// let helmet = SpaceHelmet::new().referrer_policy(ReferrerPolicy::NoReferrer); + /// ``` + pub fn referrer_policy<T: Into<Option<ReferrerPolicy>>>( + mut self, + policy: T, + ) -> SpaceHelmet<'a> { + self.referrer_policy = policy.into(); + self + } + + fn apply(&self, response: &mut Response) { + try_apply_header!(self, response, no_sniff_policy); + try_apply_header!(self, response, xss_protect_policy); + try_apply_header!(self, response, frameguard_policy); + try_apply_header!(self, response, expect_ct_policy); + try_apply_header!(self, response, referrer_policy); + if self.hsts_policy.is_some() { + try_apply_header!(self, response, hsts_policy); + } else { + if self.force_hsts.load(Ordering::Relaxed) { + try_apply_header!(self, response, force_hsts_policy); + } + } + } +} + +impl Fairing for SpaceHelmet<'static> { + fn info(&self) -> Info { + Info { + name: "Rocket SpaceHelmet (HTTP Security Headers)", + kind: Kind::Response | Kind::Launch, + } + } + + fn on_response(&self, _request: &Request, response: &mut Response) { + self.apply(response); + } + + fn on_launch(&self, rocket: &Rocket) { + if rocket.config().tls_enabled() + && !rocket.config().environment.is_dev() + && !self.hsts_policy.is_some() + { + warn_!("(Space Helmet): deploying with TLS without enabling hsts."); + warn_!("Enabling default HSTS policy."); + info_!("To disable this warning, configure an HSTS policy."); + self.force_hsts.store(true, Ordering::Relaxed); + } + } +} diff --git a/contrib/lib/src/space_helmet/mod.rs b/contrib/lib/src/space_helmet/mod.rs @@ -0,0 +1,88 @@ +//! [`SpaceHelmet`] is a [`Fairing`](/rocket/fairing/trait.Fairing.html) that +//! turns on browsers security features by adding HTTP headers to all outgoing +//! responses. +//! +//! It provides a typed interface for http security headers and takes some +//! inspiration from [helmet](https://helmetjs.github.io/), a similar piece +//! of middleware for [express](https://expressjs.com). +//! +//! ### What it supports +//! +//! | HTTP Header | Description | Method | Enabled by Default? | +//! | --------------------------- | -------------------------------------- | ---------------------------------- | ------------------- | +//! | [X-XSS-Protection] | Prevents some reflected XSS attacks. | [`SpaceHelmet::xss_protect()`] | ✔ | +//! | [X-Content-Type-Options] | Prevents client sniffing of MIME type. | [`SpaceHelmet::no_sniff()`] | ✔ | +//! | [X-Frame-Options] | Prevents [clickjacking]. | [`SpaceHelmet::frameguard()`] | ✔ | +//! | [Strict-Transport-Security] | Enforces strict use of HTTPS. | [`SpaceHelmet::hsts()`] | ? | +//! | [Expect-CT] | Enables certificate transparency. | [`SpaceHelmet::expect_ct()`] | ✗ | +//! | [Referrer-Policy] | Enables referrer policy. | [`SpaceHelmet::referrer_policy()`] | ✗ | +//! +//! [X-XSS-Protection]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection +//! [X-Content-Type-Options]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options +//! [X-Frame-Options]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options +//! [Strict-Transport-Security]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security +//! [Expect-CT]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT +//! [Referrer-Policy]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy +//! [clickjacking]: https://en.wikipedia.org/wiki/Clickjacking +//! _? If tls is enabled when a [Rocket](/rocket/struct.Rocket.html) is +//! [launched()'ed](/rocket/fairing/trait.Fairing.html) +//! in a non-development environment e.g. [Staging](/rocket/struct.Config.html#method.staging) +//! or [Production](/rocket/struct.Config.html#method.production), `SpaceHelmet` enables hsts with its +//! default policy and outputs a warning._ +//! +//! ### Examples +//! +//! To apply the headers that are enabled by default, just create a new [`SpaceHelmet`] instance +//! and attach before launch. +//! +//! ```rust +//! # extern crate rocket; +//! # extern crate rocket_contrib; +//! use rocket_contrib::space_helmet::{SpaceHelmet}; +//! +//! let rocket = rocket::ignite().attach(SpaceHelmet::new()); +//! ``` +//! +//! Each header can be configured individually if desired. To enable a particular +//! header, call the method for the header on the [`SpaceHelmet`] instance. Multiple +//! method calls can be chained in a builder pattern as illustrated below. +//! +//! ```rust +//! # extern crate rocket; +//! # extern crate rocket_contrib; +//! use rocket::http::uri::Uri; +//! +//! // Every header has a corresponding policy type. +//! use rocket_contrib::space_helmet::{SpaceHelmet, FramePolicy, XssPolicy, HstsPolicy}; +//! +//! let site_uri = Uri::parse("https://mysite.example.com").unwrap(); +//! let report_uri = Uri::parse("https://report.example.com").unwrap(); +//! let helmet = SpaceHelmet::new() +//! .hsts(HstsPolicy::default()) // each policy has a default. +//! .no_sniff(None) // setting policy to None disables the header. +//! .frameguard(FramePolicy::AllowFrom(site_uri)) +//! .xss_protect(XssPolicy::EnableReport(report_uri)); +//! ``` +//! +//! #### Still have questions? +//! +//! * _What policy should I choose?_ Check out the links in the table +//! above for individual header documentation. The [helmetjs](https://helmetjs.github.io/) doc's +//! are also a good resource, and owasp has a collection of [references] on these headers. +//! +//! [references]: https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers +//! +//! * _Where I can I read more about using fairings?_ Check out the +//! [fairing](https://rocket.rs/guide/fairings/) section of the rocket guide. +//! +//! * _Do I only need those headers `SpaceHelmet` enables by default?_ Maybe, the other headers +//! can protect against many important vulnerabilities. Please consult their documentation and +//! other resources to find out if they are needed for your project. + +extern crate time; + +mod helmet; +mod policy; + +pub use self::helmet::*; +pub use self::policy::*; diff --git a/contrib/lib/src/space_helmet/policy.rs b/contrib/lib/src/space_helmet/policy.rs @@ -0,0 +1,302 @@ +use std::borrow::Cow; +use rocket::http::uri::Uri; +use rocket::http::Header; + +use super::time::Duration; + +/// The [Referrer-Policy] header tells the browser if should send all or part of URL of the current +/// page to the next site the user navigates to via the [Referer] header. This can be important +/// for security as the URL itself might expose sensitive data, such as a hidden file path or +/// personal identifier. +/// +/// [Referrer-Policy]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy +/// [Referer]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer +pub enum ReferrerPolicy { + /// Omits the `Referer` header (_SpaceHelmet default_). + NoReferrer, + + /// Omits the `Referer` header on connection downgrade i.e. following HTTP link from HTTPS site + /// (_Browser default_). + NoReferrerWhenDowngrade, + + /// Only send the origin of part of the URL, e.g. the origin of https://foo.com/bob.html is + /// https://foo.com + Origin, + + /// Send full URL for same-origin requests, only send origin part when replying + /// to [cross-origin] requests. + /// + /// [cross-origin]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS + OriginWhenCrossOrigin, + + /// Send full URL for same-origin requests only. + SameOrigin, + + /// Only send origin part of URL, only send if protocol security level remains the same e.g. + /// HTTPS to HTTPS. + StrictOrigin, + + /// Send full URL for same-origin requests. For cross-origin requests, only send origin + /// part of URL if protocl security level remains the same e.g. HTTPS to HTTPS. + StrictOriginWhenCrossOrigin, + + /// Send full URL for same-origin or cross-origin requests. _This will leak the full + /// URL of TLS protected resources to insecure origins. Use with caution._ + UnsafeUrl, + } + +/// Defaults to [`ReferrerPolicy::NoReferrer`]. Tells the browser Omit the `Referer` header. +impl Default for ReferrerPolicy { + fn default() -> ReferrerPolicy { + ReferrerPolicy::NoReferrer + } +} + +impl<'a, 'b> From<&'a ReferrerPolicy> for Header<'b> { + fn from(policy: &ReferrerPolicy) -> Header<'b> { + let policy_string = match policy { + ReferrerPolicy::NoReferrer => "no-referrer", + ReferrerPolicy::NoReferrerWhenDowngrade => "no-referrer-when-downgrade", + ReferrerPolicy::Origin => "origin", + ReferrerPolicy::OriginWhenCrossOrigin => "origin-when-cross-origin", + ReferrerPolicy::SameOrigin => "same-origin", + ReferrerPolicy::StrictOrigin => "strict-origin", + ReferrerPolicy::StrictOriginWhenCrossOrigin => { + "strict-origin-when-cross-origin" + } + ReferrerPolicy::UnsafeUrl => "unsafe-url", + }; + + Header::new("Referrer-Policy", policy_string) + } +} + + +/// The [Expect-CT] header tells browser to enable [Certificate Transparency] checking, which +/// can detect and prevent the misuse of the site's certificate. Read all [`ExpectCtPolicy`] +/// documentation before use. +/// +/// [Certificate Transparency] +/// solves a variety of problems with public TLS/SSL certificate management and is valuable +/// measure if your standing up a public website. If your [getting started] with certificate +/// transparency, be sure that your [site is in compliance][getting started] before you turn on +/// enforcement with [`ExpectCtPolicy::Enforce`] or [`ExpectCtPolicy::ReportAndEnforce`] +/// otherwise the browser will stop talking to your site until you bring it into compliance +/// or [`Duration`] time elapses. _You have been warned_. +/// +/// +/// +/// [Expect-CT]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT +/// [Certificate Transparency]: http://www.certificate-transparency.org/what-is-ct +/// [getting started]: http://www.certificate-transparency.org/getting-started +pub enum ExpectCtPolicy<'a> { + /// Tells browser to enforce certificate compliance for [`Duration`] seconds. + /// Check if your site is in compliance before turning on enforcement. + /// (_SpaceHelmet_ default). + Enforce(Duration), + + /// Tells browser to report compliance violations certificate transparency for [`Duration`] + /// seconds. Doesn't provide any protection but is a good way make sure + /// things are working correctly before turning on enforcement in production. + Report(Duration, Uri<'a>), + + /// Enforces compliance and supports notification to if there has been a violation for + /// [`Duration`]. + ReportAndEnforce(Duration, Uri<'a>), +} + +/// Defaults to [`ExpectCtPolicy::Enforce(Duration::days(30))`], enforce CT +/// compliance, see [draft] standard for more. +/// +/// [draft]: https://tools.ietf.org/html/draft-ietf-httpbis-expect-ct-03#page-15 +impl<'a> Default for ExpectCtPolicy<'a> { + fn default() -> ExpectCtPolicy<'a> { + ExpectCtPolicy::Enforce(Duration::days(30)) + } +} + +impl<'a, 'b> From<&'a ExpectCtPolicy<'a>> for Header<'b> { + fn from(policy: &ExpectCtPolicy<'a>) -> Header<'b> { + let policy_string = match policy { + ExpectCtPolicy::Enforce(max_age) => format!("max-age={}, enforce", max_age.num_seconds()), + ExpectCtPolicy::Report(max_age, url) => { + format!("max-age={}, report-uri=\"{}\"", max_age.num_seconds(), url) + } + ExpectCtPolicy::ReportAndEnforce(max_age, url) => { + format!("max-age={}, enforce, report-uri=\"{}\"", max_age.num_seconds(), url) + } + }; + + Header::new("Expect-CT", policy_string) + } +} + +/// The [X-Content-Type-Options] header can tell the browser to turn off [mime sniffing]( +/// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#MIME_sniffing) which +/// can prevent certain [attacks]. +/// +/// [X-Content-Type-Options]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options +/// [attacks]: https://helmetjs.github.io/docs/dont-sniff-mimetype/ +pub enum NoSniffPolicy { + + ///Turns off mime sniffing. + Enable, +} + +/// Defaults to [`NoSniffPolicy::Enable`], turns off mime sniffing. +impl Default for NoSniffPolicy { + fn default() -> NoSniffPolicy { + NoSniffPolicy::Enable + } +} + +impl<'a, 'b> From<&'a NoSniffPolicy> for Header<'b> { + fn from(_policy: &NoSniffPolicy) -> Header<'b> { + Header::new("X-Content-Type-Options", "nosniff") + } +} + +/// The HTTP [Strict-Transport-Security] (HSTS) header tells the browser that the site should only +/// be accessed using HTTPS instead of HTTP. HSTS prevents a variety of downgrading attacks and +/// should always be used when TLS is enabled. `SpaceHelmet` will turn HSTS on and +/// issue a warning if you enable TLS without enabling HSTS in [Staging ] or [Production]. +/// Read full [`HstsPolicy`] documentation before you configure this. +/// +/// HSTS is important for HTTPS security, however, incorrectly configured HSTS can lead to problems as +/// you are disallowing access to non-HTTPS enabled parts of your site. [Yelp engineering] has good +/// discussion of potential challenges that can arise, and how to roll this out in a large scale setting. +/// So, if you use TLS, use HSTS, just roll it out with care. +/// +/// Finally, requiring TLS use with valid certificates may be something of a nuisance in +/// development settings, so you may with to restrict HSTS use to [Staging] and [Production]. +/// +/// [TLS]: https://rocket.rs/guide/configuration/#configuring-tls +/// [Strict-Transport-Security]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security +/// [default policy]: /rocket_contrib/space_helmet/enum.HstsPolicy.html#impl-Default +/// [Yelp engineering]: https://engineeringblog.yelp.com/2017/09/the-road-to-hsts.html +/// [Staging]: /rocket/config/enum.Environment.html#variant.Staging +/// [Production]: /rocket/config/enum.Environment.html#variant.Production +pub enum HstsPolicy { + /// Browser should only permit this site to be accesses by HTTPS for the next [`Duration`] + /// seconds. + Enable(Duration), + + /// Same as above, but also apply to all of the sites subdomains. + IncludeSubDomains(Duration), + + /// Google maintains an [HSTS preload service] that can be used to prevent + /// the browser from ever connecting to your site over an insecure connection. + /// Read more [here]. Don't enable this before you have registered your site + /// + /// [HSTS preload service]: https://hstspreload.org/ + /// [here]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security#Preloading_Strict_Transport_Security + Preload(Duration), +} + +/// Defaults to `HstsPolicy::Enable(Duration::weeks(52))`. +impl Default for HstsPolicy { + fn default() -> HstsPolicy { + HstsPolicy::Enable(Duration::weeks(52)) + } +} + +impl<'a, 'b> From<&'a HstsPolicy> for Header<'b> { + fn from(policy: &HstsPolicy) -> Header<'b> { + let policy_string = match policy { + HstsPolicy::Enable(max_age) => format!("max-age={}", max_age.num_seconds()), + HstsPolicy::IncludeSubDomains(max_age) => { + format!("max-age={}; includeSubDomains", max_age.num_seconds()) + } + HstsPolicy::Preload(max_age) => format!("max-age={}; preload", max_age.num_seconds()), + }; + + Header::new("Strict-Transport-Security", policy_string) + } +} + +/// The [X-Frame-Options] header controls whether the browser should allow the page +/// to render in a `<frame>`, [`<iframe>`][iframe] or `<object>`. This can be used +/// to prevent [clickjacking] attacks. +/// +/// +/// [X-Frame-Options]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options +/// [clickjacking]: https://en.wikipedia.org/wiki/Clickjacking +/// [owasp-clickjacking]: https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet +/// [iframe]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe +pub enum FramePolicy<'a> { + /// Page cannot be displayed in a frame. + Deny, + + /// Page can only be displayed in a frame if the page trying to render it came from + /// the same-origin. Interpretation of same-origin is [browser dependant][X-Frame-Options]. + /// + /// [X-Frame-Options]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options + SameOrigin, + + /// Page can only be displayed in a frame if the page trying to render it came from + /// the origin given `Uri`. Interpretation of origin is [browser dependant][X-Frame-Options]. + /// + /// [X-Frame-Options]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options + AllowFrom(Uri<'a>), +} + +///Defaults to [`FramePolicy::SameOrigin`]. +impl<'a> Default for FramePolicy<'a> { + fn default() -> FramePolicy<'a> { + FramePolicy::SameOrigin + } +} + +impl<'a, 'b> From<&'a FramePolicy<'a>> for Header<'b> { + fn from(policy: &FramePolicy<'a>) -> Header<'b> { + let policy_string: Cow<'static, str> = match policy { + FramePolicy::Deny => "DENY".into(), + FramePolicy::SameOrigin => "SAMEORIGIN".into(), + FramePolicy::AllowFrom(uri) => format!("ALLOW-FROM {}", uri).into(), + }; + + Header::new("X-Frame-Options", policy_string) + } +} + +/// The [X-XSS-Protection] header tells the browsers to filter some forms of reflected +/// XSS([cross-site scripting]) attacks. +/// +/// [X-XSS-Protection]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection +/// [cross-site scripting]: https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting +pub enum XssPolicy<'a> { + /// Disables XSS filtering. + Disable, + + /// Enables XSS filtering, if XSS detected browser will sanitize and render page (_often browser + /// default_). + Enable, + + /// Enables XSS filtering, if XSS detected browser will block rendering of page (_SpaceHelmet default_). + EnableBlock, + + /// Enables XSS filtering, if XSS detected browser will sanitize and render page and report the + /// violation to the given `Uri`. (Chromium only) + EnableReport(Uri<'a>), +} + +/// Defaults to [`XssPolicy::EnableBlock`], turns on XSS filtering and blocks page rendering if +/// detected. +impl<'a> Default for XssPolicy<'a> { + fn default() -> XssPolicy<'a> { + XssPolicy::EnableBlock + } +} + +impl<'a, 'b> From<&'a XssPolicy<'a>> for Header<'b> { + fn from(policy: &XssPolicy) -> Header<'b> { + let policy_string: Cow<'static, str> = match policy { + XssPolicy::Disable => "0".into(), + XssPolicy::Enable => "1".into(), + XssPolicy::EnableBlock => "1; mode=block".into(), + XssPolicy::EnableReport(u) => format!("{}{}", "1; report=", u).into(), + }; + + Header::new("X-XSS-Protection", policy_string) + } +} diff --git a/contrib/lib/tests/space_helmet.rs b/contrib/lib/tests/space_helmet.rs @@ -0,0 +1,99 @@ +#![cfg_attr(test, feature(plugin, decl_macro))] +#![cfg_attr(test, plugin(rocket_codegen))] +#![feature(proc_macro_non_items)] + +#[macro_use] extern crate rocket; +extern crate rocket_contrib; + +#[cfg(feature = "space_helmet")] +extern crate time; + +#[cfg(feature = "space_helmet")] +mod space_helmet_tests { + use rocket; + use rocket::http::uri::Uri; + use rocket::http::Status; + use rocket::local::Client; + use rocket_contrib::space_helmet::*; + use time::Duration; + + #[get("/")] + fn hello() -> &'static str { + "Hello, world!" + } + + macro_rules! check_header { + ($response:ident, $header_name:expr, $header_param:expr) => { + match $response.headers().get_one($header_name) { + Some(string) => assert_eq!(string, $header_param), + None => panic!("missing header parameters") + } + }; + } + + #[test] + fn default_headers_test() { + let helmet = SpaceHelmet::new(); + let rocket = rocket::ignite().mount("/", routes![hello]).attach(helmet); + let client = Client::new(rocket).unwrap(); + let mut response = client.get("/").dispatch(); + assert_eq!(response.status(), Status::Ok); + assert_eq!(response.body_string(), Some("Hello, world!".into())); + check_header!(response, "X-XSS-Protection", "1; mode=block"); + check_header!(response, "X-Frame-Options", "SAMEORIGIN"); + check_header!(response, "X-Content-Type-Options", "nosniff"); + } + + #[test] + fn additional_headers_test() { + let helmet = SpaceHelmet::new() + .hsts(HstsPolicy::default()) + .expect_ct(ExpectCtPolicy::default()) + .referrer_policy(ReferrerPolicy::default()); + let rocket = rocket::ignite().mount("/", routes![hello]).attach(helmet); + let client = Client::new(rocket).unwrap(); + let mut response = client.get("/").dispatch(); + assert_eq!(response.status(), Status::Ok); + assert_eq!(response.body_string(), Some("Hello, world!".into())); + check_header!( + response, + "Strict-Transport-Security", + format!("max-age={}", Duration::weeks(52).num_seconds()) + ); + check_header!( + response, + "Expect-CT", + format!("max-age={}, enforce", Duration::days(30).num_seconds()) + ); + check_header!(response, "Referrer-Policy", "no-referrer"); + } + + #[test] + fn uri_test() { + let allow_uri = Uri::parse("https://www.google.com").unwrap(); + let report_uri = Uri::parse("https://www.google.com").unwrap(); + let enforce_uri = Uri::parse("https://www.google.com").unwrap(); + let helmet = SpaceHelmet::new() + .frameguard(FramePolicy::AllowFrom(allow_uri)) + .xss_protect(XssPolicy::EnableReport(report_uri)) + .expect_ct(ExpectCtPolicy::ReportAndEnforce(Duration::seconds(30), enforce_uri)); + let rocket = rocket::ignite().mount("/", routes![hello]).attach(helmet); + let client = Client::new(rocket).unwrap(); + let response = client.get("/").dispatch(); + check_header!( + response, + "X-Frame-Options", + "ALLOW-FROM https://www.google.com" + ); + check_header!( + response, + "X-XSS-Protection", + "1; report=https://www.google.com" + ); + check_header!( + response, + "Expect-CT", + "max-age=30, enforce, report-uri=\"https://www.google.com\"" + ); + } +} diff --git a/examples/space_helmet/Cargo.toml b/examples/space_helmet/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "space_helmet" +version = "0.0.0" +workspace = "../../" +publish = false + +[dependencies] +rocket = { path = "../../core/lib", features = ["tls"]} +rocket_codegen = { path = "../../core/codegen" } + +[dependencies.rocket_contrib] +path = "../../contrib/lib" +default-features = false +features = ["space_helmet"] + +[[bin]] +name = "hello" +path = "src/hello.rs" diff --git a/examples/space_helmet/Rocket.toml b/examples/space_helmet/Rocket.toml @@ -0,0 +1,4 @@ +# Example cert and key pair from the tls example, NEVER use these in production, for demonstration only!!! +[global.tls] +certs = "private/cert.pem" +key = "private/key.pem" diff --git a/examples/space_helmet/private/cert.pem b/examples/space_helmet/private/cert.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFITCCAwmgAwIBAgIJAII1fQkonYEEMA0GCSqGSIb3DQEBCwUAMEcxCzAJBgNV +BAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEChMJUm9ja2V0IENBMRcwFQYDVQQD +Ew5Sb2NrZXQgUm9vdCBDQTAeFw0xNzA5MDExMDAyMjhaFw0yNzA4MzAxMDAyMjha +MD8xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEPMA0GA1UEChMGUm9ja2V0MRIw +EAYDVQQDEwlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDqe/Ps0tJf11HBuxJ4HvgC4VJeeiSl3D4P8ZT6uamCj8XD0MPtfRjGgfZPRjfY +ksiYRs4Wg3Wy3aiQR6IVrNAxtfU1ZA3vRGCBwV0oWkfyPJKQOtF0Ih0/MhmYdiWG +gDqs5qF/6B9K8qbinexal8v1oXpwQC5dod/NOuSLZQtQfkiYIeNqo0BbxtcaNE2u +kgOYg1Cvc9ui3KPNA2JTN+Uzq6A8n4Pej6erG2NeCAoov9nrkPyustDWLQ76wdTp +5YU6zwwsl+fJtb5scNUmagujoXTTqn06WoCMDUsSjC/jlGMIrzmx90Wq8Dg6HBGn +Cscz3M/AUXYzJtShkxMNZCsdxH+8x5oyO/RrtyeRyN8iDiOolz+SfQROVXMU0zkx +nRl7hIxgB/QeDi6MMXGLTd08vpIAohk3hnycsGgTwTCT5LxWJnorpm4wdr1bDmCY +InUO5hX0rFWtS0ij78GTUbpajkNTEXIXXwa1VnSE2kIeUX6aiKhJsm3KWp496JuM +ahIR7XCP9PyGclWI+Pa0eq5L8nnuSfqUAwCeOvvwdBOxUvKmecly1IHLoUXGnhy0 +46MjYo80yYFqrGgop6lUEZ0ThYpDpMxq+JIeUoyGaCJFDvundzt0u0sh9i+hUCVe +v3zsgxwvBeJy0L1G1uGkpCqERkYJQt9O+qLM8i7hf7ONkQIDAQABoxgwFjAUBgNV +HREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQELBQADggIBAAcXycXdWVvwLl+7 +ryG8V7FpB9bp0lHNA4q3DpEINCNyuA2cbnVU/u2L3ddvroTcrPjE+hhNbcVaz/NH +w4sQqlDzkV+G9kZ4qBTlk5zon6aGGow181J+B5SVznt6lO4/KYYpEN0vX+uMvsgK +OG7ydsRMDxPpsnVS9SFx0Ke8AlmUet5S/NGYCfedd4rwCu+oJHUWhXNwFZqLF3Yn +s8lg3xdM0kJt8g4m1/KUpunanX3w+DdZaIwbltEZs4NriXn0VVbEPRpHyiGMosgf +mEUV2z49f6S2joEnSn2Y/ILOdKFQ2mKFXtXJP43Qzj8Mr5mSb2bXyABlrn0pl/+o +HBkyVyDx5BKqWKe5uK3YCDsbIJj026AkCdTKF+BSBWfB+EqdSIOvVrpHtQK7BwFx +pS5rdQBLA86f1NC0e235L6pwFKm+imazr6Jn7fbbwq1y9PSL36rUn4e/+R2Yoia9 +S7zDOqGbnyv9h7eE3Muiy26kJsJfCrjse/dmce+6YnB1FC5RKPn7kM86t7MyDrgx +W60xRMdgmcGfPjei2V4MdVM6ysOlNoeh39DizjkV9+r8iGl4vngplJrPgAIvywQz +v1pLk6dSlSOwgqY94hqxqNvG80xSoYsmMjDrPmtBVERjhbffsdIDHjcPVsJKH6l6 +8wg+/u6aK2bMHt41f3XE/UTY+A57 +-----END CERTIFICATE----- diff --git a/examples/space_helmet/private/key.pem b/examples/space_helmet/private/key.pem @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/examples/space_helmet/src/hello.rs b/examples/space_helmet/src/hello.rs @@ -0,0 +1,33 @@ +#![feature(decl_macro)] +#![feature(plugin)] +#![plugin(rocket_codegen)] +#![feature(proc_macro_non_items)] + +#[macro_use] extern crate rocket; +extern crate rocket_contrib; +use rocket::http::uri::Uri; + +use rocket_contrib::space_helmet::*; + +#[get("/")] +fn index() -> &'static str { + "Hello, world!" +} + +fn rocket() -> rocket::Rocket { + let allow_uri = Uri::parse("https://mysite.example.com").unwrap(); + let report_uri = Uri::parse("https://report.example.com").unwrap(); + let helmet = SpaceHelmet::new() + //illustrates how to disable a header by using None as the policy. + .no_sniff(None) + .frameguard(FramePolicy::AllowFrom(allow_uri)) + .xss_protect(XssPolicy::EnableReport(report_uri)) + //we need an hsts policy as we are using tls + .hsts(HstsPolicy::default()) + .expect_ct(ExpectCtPolicy::default()); + rocket::ignite().mount("/", routes![index]).attach(helmet) +} + +fn main() { + rocket().launch(); +} diff --git a/scripts/test.sh b/scripts/test.sh @@ -86,6 +86,7 @@ if [ "$1" = "--contrib" ]; then tera_templates handlebars_templates serve + space_helmet diesel_postgres_pool diesel_sqlite_pool diesel_mysql_pool