commit 1bb23b81159c4a63409f1eff2f21a10ee9437a60
parent c5167f1150dd602d0f84e695c5d4fe31b5dff5fc
Author: Sergio Benitez <sb@sergio.bz>
Date: Thu, 8 Nov 2018 09:01:58 -0800
Rename 'space_helmet' to 'helmet'. Rework API.
Diffstat:
17 files changed, 855 insertions(+), 918 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -8,7 +8,6 @@ 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,7 +21,7 @@ json = ["serde", "serde_json"]
msgpack = ["serde", "rmp-serde"]
tera_templates = ["tera", "templates"]
handlebars_templates = ["handlebars", "templates"]
-space_helmet = ["time"]
+helmet = ["time"]
serve = []
# The barage of user-facing database features.
@@ -73,8 +73,5 @@ 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/helmet/helmet.rs b/contrib/lib/src/helmet/helmet.rs
@@ -0,0 +1,212 @@
+use std::collections::HashMap;
+use std::sync::atomic::{AtomicBool, Ordering};
+
+use rocket::http::uncased::UncasedStr;
+use rocket::fairing::{Fairing, Info, Kind};
+use rocket::{Request, Response, Rocket};
+
+use helmet::*;
+
+/// A [`Fairing`](../../rocket/fairing/trait.Fairing.html) that adds HTTP
+/// headers to outgoing responses that control security features on the browser.
+///
+/// # Usage
+///
+/// To use `SpaceHelmet`, first construct an instance of it. To use the default
+/// set of headers, construct with [`SpaceHelmet::default()`](#method.default).
+/// For an instance with no preset headers, use [`SpaceHelmet::new()`]. To
+/// enable an additional header, use [`enable()`](SpaceHelmet::enable()), and to
+/// disable a header, use [`disable()`](SpaceHelmet::disable()):
+///
+/// ```rust
+/// use rocket_contrib::helmet::SpaceHelmet;
+/// use rocket_contrib::helmet::{XssFilter, ExpectCt};
+///
+/// // A `SpaceHelmet` with the default headers:
+/// let helmet = SpaceHelmet::default();
+///
+/// // A `SpaceHelmet` with the default headers minus `XssFilter`:
+/// let helmet = SpaceHelmet::default().disable::<XssFilter>();
+///
+/// // A `SpaceHelmet` with the default headers plus `ExpectCt`.
+/// let helmet = SpaceHelmet::default().enable(ExpectCt::default());
+///
+/// // A `SpaceHelmet` with only `XssFilter` and `ExpectCt`.
+/// let helmet = SpaceHelmet::default()
+/// .enable(XssFilter::default())
+/// .enable(ExpectCt::default());
+/// ```
+///
+/// Then, attach the instance of `SpaceHelmet` to your application's instance of
+/// `Rocket`:
+///
+/// ```rust
+/// # extern crate rocket;
+/// # extern crate rocket_contrib;
+/// # use rocket_contrib::helmet::SpaceHelmet;
+/// # let helmet = SpaceHelmet::default();
+/// rocket::ignite()
+/// // ...
+/// .attach(helmet)
+/// # ;
+/// ```
+///
+/// The fairing will inject all enabled headers into all outgoing responses
+/// _unless_ the response already contains a header with the same name. If it
+/// does contain the header, a warning is emitted, and the header is not
+/// overwritten.
+///
+/// # TLS and HSTS
+///
+/// If TLS is configured and enabled when the application is launched in a
+/// non-development environment (e.g., staging or production), HSTS is
+/// automatically enabled with its default policy and a warning is issued.
+///
+/// To get rid of this warning, explicitly [`enable()`](SpaceHelmet::enable())
+/// an [`Hsts`] policy.
+pub struct SpaceHelmet {
+ policies: HashMap<&'static UncasedStr, Box<dyn SubPolicy>>,
+ force_hsts: AtomicBool,
+}
+
+impl Default for SpaceHelmet {
+ /// Returns a new `SpaceHelmet` instance. See the [table] for a description
+ /// of the policies used by default.
+ ///
+ /// [table]: ./#supported-headers
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # extern crate rocket;
+ /// # extern crate rocket_contrib;
+ /// use rocket_contrib::helmet::SpaceHelmet;
+ ///
+ /// let helmet = SpaceHelmet::default();
+ /// ```
+ fn default() -> Self {
+ SpaceHelmet::new()
+ .enable(NoSniff::default())
+ .enable(Frame::default())
+ .enable(XssFilter::default())
+ }
+}
+
+impl SpaceHelmet {
+ /// Returns an instance of `SpaceHelmet` with no headers enabled.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use rocket_contrib::helmet::SpaceHelmet;
+ ///
+ /// let helmet = SpaceHelmet::new();
+ /// ```
+ pub fn new() -> Self {
+ SpaceHelmet {
+ policies: HashMap::new(),
+ force_hsts: AtomicBool::new(false),
+ }
+ }
+
+ /// Enables the policy header `policy`.
+ ///
+ /// If the poliicy was previously enabled, the configuration is replaced
+ /// with that of `policy`.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use rocket_contrib::helmet::SpaceHelmet;
+ /// use rocket_contrib::helmet::NoSniff;
+ ///
+ /// let helmet = SpaceHelmet::new().enable(NoSniff::default());
+ /// ```
+ pub fn enable<P: Policy>(mut self, policy: P) -> Self {
+ self.policies.insert(P::NAME.into(), Box::new(policy));
+ self
+ }
+
+ /// Disables the policy header `policy`.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use rocket_contrib::helmet::SpaceHelmet;
+ /// use rocket_contrib::helmet::NoSniff;
+ ///
+ /// let helmet = SpaceHelmet::default().disable::<NoSniff>();
+ /// ```
+ pub fn disable<P: Policy>(mut self) -> Self {
+ self.policies.remove(UncasedStr::new(P::NAME));
+ self
+ }
+
+ /// Returns `true` if the policy `P` is enabled.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use rocket_contrib::helmet::SpaceHelmet;
+ /// use rocket_contrib::helmet::{XssFilter, NoSniff, Frame};
+ /// use rocket_contrib::helmet::{Hsts, ExpectCt, Referrer};
+ ///
+ /// let helmet = SpaceHelmet::default();
+ ///
+ /// assert!(helmet.is_enabled::<XssFilter>());
+ /// assert!(helmet.is_enabled::<NoSniff>());
+ /// assert!(helmet.is_enabled::<Frame>());
+ ///
+ /// assert!(!helmet.is_enabled::<Hsts>());
+ /// assert!(!helmet.is_enabled::<ExpectCt>());
+ /// assert!(!helmet.is_enabled::<Referrer>());
+ /// ```
+ pub fn is_enabled<P: Policy>(&self) -> bool {
+ self.policies.contains_key(UncasedStr::new(P::NAME))
+ }
+
+ /// Sets all of the headers in `self.policies` in `response` as long as the
+ /// header is not already in the response.
+ fn apply(&self, response: &mut Response) {
+ for policy in self.policies.values() {
+ let name = policy.name();
+ if response.headers().contains(name.as_str()) {
+ warn!("Space Helmet: response contains a '{}' header.", name);
+ warn_!("Refusing to overwrite existing header.");
+ continue
+ }
+
+ // FIXME: Cache the rendered header.
+ response.set_header(policy.header());
+ }
+
+ if !self.force_hsts.load(Ordering::Relaxed) {
+ response.set_header(Policy::header(&Hsts::default()));
+ }
+ }
+}
+
+impl Fairing for SpaceHelmet {
+ fn info(&self) -> Info {
+ Info {
+ name: "Space Helmet",
+ 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.is_enabled::<Hsts>()
+ {
+ 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/helmet/mod.rs b/contrib/lib/src/helmet/mod.rs
@@ -0,0 +1,100 @@
+//! Security and privacy headers for all outgoing responses.
+//!
+//! [`SpaceHelmet`] provides a typed interface for HTTP security headers. It
+//! takes some inspiration from [helmetjs], a similar piece of middleware for
+//! [express].
+//!
+//! [fairing]: https://rocket.rs/v0.4/guide/fairings/
+//! [helmetjs]: https://helmetjs.github.io/
+//! [express]: https://expressjs.com
+//! [`SpaceHelmet`]: helmet::SpaceHelmet
+//!
+//! # Supported Headers
+//!
+//! | HTTP Header | Description | Policy | Default? |
+//! | --------------------------- | -------------------------------------- | ------------ | -------- |
+//! | [X-XSS-Protection] | Prevents some reflected XSS attacks. | [`XssFilter`] | ✔ |
+//! | [X-Content-Type-Options] | Prevents client sniffing of MIME type. | [`NoSniff`] | ✔ |
+//! | [X-Frame-Options] | Prevents [clickjacking]. | [`Frame`] | ✔ |
+//! | [Strict-Transport-Security] | Enforces strict use of HTTPS. | [`Hsts`] | ? |
+//! | [Expect-CT] | Enables certificate transparency. | [`ExpectCt`] | ✗ |
+//! | [Referrer-Policy] | Enables referrer policy. | [`Referrer`] | ✗ |
+//!
+//! <small>? If TLS is enabled when the application is launched, in a
+//! non-development environment (e.g., staging or production), HSTS is
+//! automatically enabled with its default policy and a warning is
+//! issued.</small>
+//!
+//! [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
+//!
+//! [`XssFilter`]: helmet::XssFilter
+//! [`NoSniff`]: helmet::NoSniff
+//! [`Frame`]: helmet::Frame
+//! [`Hsts`]: helmet::Hsts
+//! [`ExpectCt`]: helmet::ExpectCt
+//! [`Referrer`]: helmet::Referrer
+//!
+//! # Usage
+//!
+//! To apply default headers, simply attach an instance of [`SpaceHelmet`]
+//! before launching:
+//!
+//! ```rust
+//! # extern crate rocket;
+//! # extern crate rocket_contrib;
+//! use rocket_contrib::helmet::SpaceHelmet;
+//!
+//! let rocket = rocket::ignite().attach(SpaceHelmet::default());
+//! ```
+//!
+//! Each header can be configured individually. To enable a particular header,
+//! call the chainable [`enable()`](helmet::SpaceHelmet::enable()) method
+//! on an instance of `SpaceHelmet`, passing in the configured policy type.
+//! Similarly, to disable a header, call the chainable
+//! [`disable()`](helmet::SpaceHelmet::disable()) method on an instance of
+//! `SpaceHelmet`:
+//!
+//! ```rust
+//! # extern crate rocket;
+//! # extern crate rocket_contrib;
+//! use rocket::http::uri::Uri;
+//! use rocket_contrib::helmet::{SpaceHelmet, Frame, XssFilter, Hsts, NoSniff};
+//!
+//! let site_uri = Uri::parse("https://mysite.example.com").unwrap();
+//! let report_uri = Uri::parse("https://report.example.com").unwrap();
+//! let helmet = SpaceHelmet::default()
+//! .enable(Hsts::default())
+//! .enable(Frame::AllowFrom(site_uri))
+//! .enable(XssFilter::EnableReport(report_uri))
+//! .disable::<NoSniff>();
+//! ```
+//!
+//! # FAQ
+//!
+//! * **Which policies should I choose?**
+//!
+//! See the links in the table above for individual header documentation. The
+//! [helmetjs] docs are also a good resource, and [OWASP] has a collection of
+//! references on these headers.
+//!
+//! * **Do I need any headers beyond what `SpaceHelmet` enables by default?**
+//!
+//! Maybe! The other headers can protect against many important
+//! vulnerabilities. Please consult their documentation and other resources to
+//! determine if they are needed for your project.
+//!
+//! [OWASP]: https://www.owasp.org/index.php/OWASP_Secure_Headers_Project#tab=Headers
+
+extern crate time;
+
+mod helmet;
+mod policy;
+
+pub use self::helmet::SpaceHelmet;
+pub use self::policy::*;
diff --git a/contrib/lib/src/helmet/policy.rs b/contrib/lib/src/helmet/policy.rs
@@ -0,0 +1,401 @@
+//! Module containing the [`Policy`] trait and types that implement it.
+
+use std::borrow::Cow;
+
+use rocket::http::{Header, uri::Uri, uncased::UncasedStr};
+
+use helmet::time::Duration;
+
+/// Trait implemented by security and privacy policy headers.
+///
+/// Types that implement this trait can be [`enable()`]d and [`disable()`]d on
+/// instances of [`SpaceHelmet`].
+///
+/// [`SpaceHelmet`]: ::helmet::SpaceHelmet
+/// [`enable()`]: ::helmet::SpaceHelmet::enable()
+/// [`disable()`]: ::helmet::SpaceHelmet::disable()
+pub trait Policy: Default + Send + Sync + 'static {
+ /// The actual name of the HTTP header.
+ ///
+ /// This name must uniquely identify the header as it is used to determine
+ /// whether two implementations of `Policy` are for the same header. Use the
+ /// real HTTP header's name.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # extern crate rocket;
+ /// # extern crate rocket_contrib;
+ /// # use rocket::http::Header;
+ /// use rocket_contrib::helmet::Policy;
+ ///
+ /// #[derive(Default)]
+ /// struct MyPolicy;
+ ///
+ /// impl Policy for MyPolicy {
+ /// const NAME: &'static str = "X-My-Policy";
+ /// # fn header(&self) -> Header<'static> { unimplemented!() }
+ /// }
+ /// ```
+ const NAME: &'static str;
+
+ /// Returns the [`Header`](../../rocket/http/struct.Header.html) to attach
+ /// to all outgoing responses.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # extern crate rocket;
+ /// # extern crate rocket_contrib;
+ /// use rocket::http::Header;
+ /// use rocket_contrib::helmet::Policy;
+ ///
+ /// #[derive(Default)]
+ /// struct MyPolicy;
+ ///
+ /// impl Policy for MyPolicy {
+ /// # const NAME: &'static str = "X-My-Policy";
+ /// fn header(&self) -> Header<'static> {
+ /// Header::new(Self::NAME, "value-to-enable")
+ /// }
+ /// }
+ /// ```
+ fn header(&self) -> Header<'static>;
+}
+
+crate trait SubPolicy: Send + Sync {
+ fn name(&self) -> &'static UncasedStr;
+ fn header(&self) -> Header<'static>;
+}
+
+impl<P: Policy> SubPolicy for P {
+ fn name(&self) -> &'static UncasedStr {
+ P::NAME.into()
+ }
+
+ fn header(&self) -> Header<'static> {
+ Policy::header(self)
+ }
+}
+
+macro_rules! impl_policy {
+ ($T:ty, $name:expr) => (
+ impl Policy for $T {
+ const NAME: &'static str = $name;
+
+ fn header(&self) -> Header<'static> {
+ self.into()
+ }
+ }
+ )
+}
+
+impl_policy!(XssFilter, "X-XSS-Protection");
+impl_policy!(NoSniff, "X-Content-Type-Options");
+impl_policy!(Frame, "X-Frame-Options");
+impl_policy!(Hsts, "Strict-Transport-Security");
+impl_policy!(ExpectCt, "Expect-CT");
+impl_policy!(Referrer, "Referrer-Policy");
+
+/// The [Referrer-Policy] header: controls the value set by the browser for the
+/// [Referer] header.
+///
+/// Tells the browser if it 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 Referrer {
+ /// 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 [`Referrer::NoReferrer`]. Tells the browser to omit the
+/// `Referer` header.
+impl Default for Referrer {
+ fn default() -> Referrer {
+ Referrer::NoReferrer
+ }
+}
+
+impl<'h, 'a> Into<Header<'h>> for &'a Referrer {
+ fn into(self) -> Header<'h> {
+ let policy_string = match self {
+ Referrer::NoReferrer => "no-referrer",
+ Referrer::NoReferrerWhenDowngrade => "no-referrer-when-downgrade",
+ Referrer::Origin => "origin",
+ Referrer::OriginWhenCrossOrigin => "origin-when-cross-origin",
+ Referrer::SameOrigin => "same-origin",
+ Referrer::StrictOrigin => "strict-origin",
+ Referrer::StrictOriginWhenCrossOrigin => "strict-origin-when-cross-origin",
+ Referrer::UnsafeUrl => "unsafe-url",
+ };
+
+ Header::new(Referrer::NAME, policy_string)
+ }
+}
+
+/// The [Expect-CT] header: enables [Certificate Transparency] to detect and
+/// prevent misuse of TLS certificates.
+///
+/// [Certificate Transparency] solves a variety of problems with public TLS/SSL
+/// certificate management and is valuable measure for all public applications.
+/// If you're just [getting started] with certificate transparency, ensure that
+/// your [site is in compliance][getting started] before you enable enforcement
+/// with [`ExpectCt::Enforce`] or [`ExpectCt::ReportAndEnforce`]. Failure to do
+/// so will result in the browser refusing to communicate with your application.
+/// _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 ExpectCt {
+ /// Enforce certificate compliance for the next [`Duration`]. Ensure that
+ /// your certificates are in compliance before turning on enforcement.
+ /// (_SpaceHelmet_ default).
+ Enforce(Duration),
+
+ /// Report to `Uri`, but do not enforce, compliance violations for the next
+ /// [`Duration`]. 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<'static>),
+
+ /// Enforce compliance and report violations to `Uri` for the next
+ /// [`Duration`].
+ ReportAndEnforce(Duration, Uri<'static>),
+}
+
+/// Defaults to [`ExpectCt::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 Default for ExpectCt {
+ fn default() -> ExpectCt {
+ ExpectCt::Enforce(Duration::days(30))
+ }
+}
+
+impl<'a> Into<Header<'static>> for &'a ExpectCt {
+ fn into(self) -> Header<'static> {
+ let policy_string = match self {
+ ExpectCt::Enforce(age) => format!("max-age={}, enforce", age.num_seconds()),
+ ExpectCt::Report(age, uri) => {
+ format!(r#"max-age={}, report-uri="{}""#, age.num_seconds(), uri)
+ }
+ ExpectCt::ReportAndEnforce(age, uri) => {
+ format!("max-age={}, enforce, report-uri=\"{}\"", age.num_seconds(), uri)
+ }
+ };
+
+ Header::new(ExpectCt::NAME, policy_string)
+ }
+}
+
+/// The [X-Content-Type-Options] header: turns off [mime sniffing] which can
+/// prevent certain [attacks].
+///
+/// [mime sniffing]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#MIME_sniffing
+/// [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 NoSniff {
+ /// Turns off mime sniffing.
+ Enable,
+}
+
+/// Defaults to [`NoSniff::Enable`], turns off mime sniffing.
+impl Default for NoSniff {
+ fn default() -> NoSniff {
+ NoSniff::Enable
+ }
+}
+
+impl<'h, 'a> Into<Header<'h>> for &'a NoSniff {
+ fn into(self) -> Header<'h> {
+ Header::new(NoSniff::NAME, "nosniff")
+ }
+}
+
+/// The HTTP [Strict-Transport-Security] (HSTS) header: enforces strict HTTPS
+/// usage.
+///
+/// HSTS 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 when the application
+/// is run in the staging or production environments.
+///
+/// While HSTS is important for HTTPS security, 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, but roll it out with care.
+///
+/// [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/helmet/enum.Hsts.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 Hsts {
+ /// Browser should only permit this site to be accesses by HTTPS for the
+ /// next [`Duration`].
+ Enable(Duration),
+
+ /// Like [`Hsts::Enable`], but also apply to all of the site's 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 `Hsts::Enable(Duration::weeks(52))`.
+impl Default for Hsts {
+ fn default() -> Hsts {
+ Hsts::Enable(Duration::weeks(52))
+ }
+}
+
+impl<'a> Into<Header<'static>> for &'a Hsts {
+ fn into(self) -> Header<'static> {
+ let policy_string = match self {
+ Hsts::Enable(age) => format!("max-age={}", age.num_seconds()),
+ Hsts::IncludeSubDomains(age) => {
+ format!("max-age={}; includeSubDomains", age.num_seconds())
+ }
+ Hsts::Preload(age) => format!("max-age={}; preload", age.num_seconds()),
+ };
+
+ Header::new(Hsts::NAME, policy_string)
+ }
+}
+
+/// The [X-Frame-Options] header: helps prevent [clickjacking] attacks.
+///
+/// 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 Frame {
+ /// Page cannot be displayed in a frame.
+ Deny,
+
+ /// Page can only be displayed in a frame if the page trying to render it is
+ /// in the same origin. Interpretation of same-origin is [browser
+ /// dependent][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 is
+ /// in the origin for `Uri`. Interpretation of origin is [browser
+ /// dependent][X-Frame-Options].
+ ///
+ /// [X-Frame-Options]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ AllowFrom(Uri<'static>),
+}
+
+/// Defaults to [`Frame::SameOrigin`].
+impl Default for Frame {
+ fn default() -> Frame {
+ Frame::SameOrigin
+ }
+}
+
+impl<'a> Into<Header<'static>> for &'a Frame {
+ fn into(self) -> Header<'static> {
+ let policy_string: Cow<'static, str> = match self {
+ Frame::Deny => "DENY".into(),
+ Frame::SameOrigin => "SAMEORIGIN".into(),
+ Frame::AllowFrom(uri) => format!("ALLOW-FROM {}", uri).into(),
+ };
+
+ Header::new(Frame::NAME, policy_string)
+ }
+}
+
+/// The [X-XSS-Protection] header: filters some forms of reflected [XSS]
+/// attacks.
+///
+/// [X-XSS-Protection]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection
+/// [XSS]: https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting
+pub enum XssFilter {
+ /// Disables XSS filtering.
+ Disable,
+
+ /// Enables XSS filtering. If XSS is detected, the browser will sanitize
+ /// before rendering the page (_SpaceHelmet default_).
+ Enable,
+
+ /// Enables XSS filtering. If XSS is detected, the browser will not
+ /// render the page.
+ EnableBlock,
+
+ /// Enables XSS filtering. If XSS is detected, the browser will sanitize and
+ /// render the page and report the violation to the given `Uri`. (_Chromium
+ /// only_)
+ EnableReport(Uri<'static>),
+}
+
+/// Defaults to [`XssFilter::Enable`].
+impl Default for XssFilter {
+ fn default() -> XssFilter {
+ XssFilter::Enable
+ }
+}
+
+impl<'a> Into<Header<'static>> for &'a XssFilter {
+ fn into(self) -> Header<'static> {
+ let policy_string: Cow<'static, str> = match self {
+ XssFilter::Disable => "0".into(),
+ XssFilter::Enable => "1".into(),
+ XssFilter::EnableBlock => "1; mode=block".into(),
+ XssFilter::EnableReport(u) => format!("{}{}", "1; report=", u).into(),
+ };
+
+ Header::new(XssFilter::NAME, policy_string)
+ }
+}
diff --git a/contrib/lib/src/lib.rs b/contrib/lib/src/lib.rs
@@ -24,7 +24,7 @@
//! * [tera_templates](templates) - Tera Templating
//! * [uuid](uuid) - UUID (de)serialization
//! * [${database}_pool](databases) - Database Configuration and Pooling
-//! * [space_helmet](space_helmet)
+//! * [helmet](helmet) - Fairing for Security and Privacy Headers
//!
//! The recommend way to include features from this crate via Cargo in your
//! project is by adding a `[dependencies.rocket_contrib]` section to your
@@ -50,7 +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 = "helmet")] pub mod 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
@@ -1,285 +0,0 @@
-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
@@ -1,88 +0,0 @@
-//! [`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
@@ -1,302 +0,0 @@
-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/helmet.rs b/contrib/lib/tests/helmet.rs
@@ -0,0 +1,138 @@
+#![feature(proc_macro_hygiene, decl_macro)]
+
+#[macro_use]
+#[cfg(feature = "helmet")]
+extern crate rocket;
+
+#[cfg(feature = "helmet")]
+mod helmet_tests {
+ extern crate time;
+ extern crate rocket_contrib;
+
+ use rocket;
+ use rocket::http::{Status, uri::Uri};
+ use rocket::local::{Client, LocalResponse};
+
+ use self::rocket_contrib::helmet::*;
+ use self::rocket_contrib::helmet::*;
+ use self::time::Duration;
+
+ #[get("/")] fn hello() { }
+
+ macro_rules! assert_header {
+ ($response:ident, $name:expr, $value:expr) => {
+ match $response.headers().get_one($name) {
+ Some(value) => assert_eq!(value, $value),
+ None => panic!("missing header '{}' with value '{}'", $name, $value)
+ }
+ };
+ }
+
+ macro_rules! assert_no_header {
+ ($response:ident, $name:expr) => {
+ if let Some(value) = $response.headers().get_one($name) {
+ panic!("unexpected header: '{}={}", $name, value);
+ }
+ };
+ }
+
+ macro_rules! dispatch {
+ ($helmet:expr, $closure:expr) => {{
+ let rocket = rocket::ignite().mount("/", routes![hello]).attach($helmet);
+ let client = Client::new(rocket).unwrap();
+ let response = client.get("/").dispatch();
+ assert_eq!(response.status(), Status::Ok);
+ $closure(response)
+ }}
+ }
+
+ #[test]
+ fn default_headers_test() {
+ dispatch!(SpaceHelmet::default(), |response: LocalResponse| {
+ assert_header!(response, "X-XSS-Protection", "1");
+ assert_header!(response, "X-Frame-Options", "SAMEORIGIN");
+ assert_header!(response, "X-Content-Type-Options", "nosniff");
+ })
+ }
+
+ #[test]
+ fn disable_headers_test() {
+ let helmet = SpaceHelmet::default().disable::<XssFilter>();
+ dispatch!(helmet, |response: LocalResponse| {
+ assert_header!(response, "X-Frame-Options", "SAMEORIGIN");
+ assert_header!(response, "X-Content-Type-Options", "nosniff");
+ assert_no_header!(response, "X-XSS-Protection");
+ });
+
+ let helmet = SpaceHelmet::default().disable::<Frame>();
+ dispatch!(helmet, |response: LocalResponse| {
+ assert_header!(response, "X-XSS-Protection", "1");
+ assert_header!(response, "X-Content-Type-Options", "nosniff");
+ assert_no_header!(response, "X-Frame-Options");
+ });
+
+ let helmet = SpaceHelmet::default()
+ .disable::<Frame>()
+ .disable::<XssFilter>()
+ .disable::<NoSniff>();
+
+ dispatch!(helmet, |response: LocalResponse| {
+ assert_no_header!(response, "X-Frame-Options");
+ assert_no_header!(response, "X-XSS-Protection");
+ assert_no_header!(response, "X-Content-Type-Options");
+ });
+
+ dispatch!(SpaceHelmet::new(), |response: LocalResponse| {
+ assert_no_header!(response, "X-Frame-Options");
+ assert_no_header!(response, "X-XSS-Protection");
+ assert_no_header!(response, "X-Content-Type-Options");
+ });
+ }
+
+ #[test]
+ fn additional_headers_test() {
+ let helmet = SpaceHelmet::default()
+ .enable(Hsts::default())
+ .enable(ExpectCt::default())
+ .enable(Referrer::default());
+
+ dispatch!(helmet, |response: LocalResponse| {
+ assert_header!(
+ response,
+ "Strict-Transport-Security",
+ format!("max-age={}", Duration::weeks(52).num_seconds())
+ );
+
+ assert_header!(
+ response,
+ "Expect-CT",
+ format!("max-age={}, enforce", Duration::days(30).num_seconds())
+ );
+
+ assert_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::default()
+ .enable(Frame::AllowFrom(allow_uri))
+ .enable(XssFilter::EnableReport(report_uri))
+ .enable(ExpectCt::ReportAndEnforce(Duration::seconds(30), enforce_uri));
+
+ dispatch!(helmet, |response: LocalResponse| {
+ assert_header!(response, "X-Frame-Options",
+ "ALLOW-FROM https://www.google.com");
+
+ assert_header!(response, "X-XSS-Protection",
+ "1; report=https://www.google.com");
+
+ assert_header!(response, "Expect-CT",
+ "max-age=30, enforce, report-uri=\"https://www.google.com\"");
+ });
+ }
+}
diff --git a/contrib/lib/tests/space_helmet.rs b/contrib/lib/tests/space_helmet.rs
@@ -1,99 +0,0 @@
-#![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
@@ -1,18 +0,0 @@
-[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
@@ -1,4 +0,0 @@
-# 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
@@ -1,30 +0,0 @@
------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
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKAIBAAKCAgEA6nvz7NLSX9dRwbsSeB74AuFSXnokpdw+D/GU+rmpgo/Fw9DD
-7X0YxoH2T0Y32JLImEbOFoN1st2okEeiFazQMbX1NWQN70RggcFdKFpH8jySkDrR
-dCIdPzIZmHYlhoA6rOahf+gfSvKm4p3sWpfL9aF6cEAuXaHfzTrki2ULUH5ImCHj
-aqNAW8bXGjRNrpIDmINQr3PbotyjzQNiUzflM6ugPJ+D3o+nqxtjXggKKL/Z65D8
-rrLQ1i0O+sHU6eWFOs8MLJfnybW+bHDVJmoLo6F006p9OlqAjA1LEowv45RjCK85
-sfdFqvA4OhwRpwrHM9zPwFF2MybUoZMTDWQrHcR/vMeaMjv0a7cnkcjfIg4jqJc/
-kn0ETlVzFNM5MZ0Ze4SMYAf0Hg4ujDFxi03dPL6SAKIZN4Z8nLBoE8Ewk+S8ViZ6
-K6ZuMHa9Ww5gmCJ1DuYV9KxVrUtIo+/Bk1G6Wo5DUxFyF18GtVZ0hNpCHlF+moio
-SbJtylqePeibjGoSEe1wj/T8hnJViPj2tHquS/J57kn6lAMAnjr78HQTsVLypnnJ
-ctSBy6FFxp4ctOOjI2KPNMmBaqxoKKepVBGdE4WKQ6TMaviSHlKMhmgiRQ77p3c7
-dLtLIfYvoVAlXr987IMcLwXictC9RtbhpKQqhEZGCULfTvqizPIu4X+zjZECAwEA
-AQKCAgAxmpc3ekHW1I4PFawKjUKaGWB7bAtkqvrWFJ0XjT82x4NmsTtBej1LgSLC
-EnCt+B9HV3MxgA3eENYf74dyXmSMn5mH+eqYuzZPPMCgULj3najDqi21C6J0Q/z2
-K8g0c9v1x7RSgqBcEokLV60wXPxgshBcvrcQR7Y4jETc2DtUg+KHjGO3o2FyCNZo
-TLhCPdFU6jKfazsDcPmV3SlnwWNTUvNK39PduTYXFGwo8Dp19F/9XWaW7m0PYejR
-Uz/fWxacIkDJDjmSikgGWLg+sCBWNUmpnV9wgMTA2+8NtWpMEpAAvlDOPSkXyEmc
-wWNamwUZC5VHcfQ3TfedVqepJY+ZDNNaZ6O+GH7Qe33jxdyXbt8CSEI52lDDotfX
-rwjI8//qnoDGmwzBNThBTjXyrAbwn/KzfYXvPMfMd1GB2YPG0WmcZhFNuEm6f4Pf
-5vhQldT/Wd1RBbGTVDYo/49uSNAwTu9ObW7o50obUfyW0bUgopBaZBwRfOBFJ1QU
-PFCRqCv16STPr8AaeP2nlZawsC5ECbzdBRxvHG6P2FCOdgclWhZNlMdRydFTI5QJ
-aAfgkHYT8DFtZ/P0fbc2csFaOWNd3vSp07TCgqff6vgR8jGJDRnC+Oq4Q8rERiFw
-A7O/TzjYskY8aMkM4mvSfmnqo7Qqv+XPgDbfWi9tq8nrDYzSAQKCAQEA+VAUqyCN
-DvtkMGbd8AyYNx738K3Sea+/t+y2X1V1q93+TKypcrpZ0KhrnKGxf2UnJZx31NOX
-vdXUwNu/I9/lnOuJlR7yVC0E185v+j0GQRZRjwTv6qUEBnHRViEkpy0j3INiVg8t
-aLbrg5NoD4vlgocSFP2IDD+dFkDS4oKebXfuQFtvW8qd769RzjQAGHTje+Fk1US/
-ADgDPINoZOyhuyA9r8Q9BfrhksliB80a3q+ieHPpaYAa+9NT6B3SZfVgzblj4mfs
-nHDAor4ZYpJ6sLB5pcUG5DILVx1ncO2S0qO53w3P5j4jatz4KZWheOSQQkSCWwP5
-qAEMw28tv0ezmQKCAQEA8MYM8v/3FRlct/lLCzA+Smq+ZvdXyTpM9fICvSaBD6WT
-/xYguTUbzWB8WBzMCDK3quttBrWCMIRWzEfEPE51db+0MycoAjM7sw2nql3tgFy5
-OZV4g5lzPnWsh76ba8xq2x5h8j1sbsvTWZoxD5/fcXEEAvwMFTvgm39T+NyMoAZ0
-PMO3x7sZiI5GLLZ5wmjlb1dEbxHujPIJNuSJtdNjecRhyhPcairK8dfjQaStgyE3
-O9hGCBYOzz0n4O76dJmH1g1HAmG4RvZU6zC3lDITXhgQ9pVH50qS1oI7jLhn3QoY
-SfdZ+LDC/8nDVcPLX+JFL95ha80o/K5PQ7uWXXNkuQKCAQEAuASwzMLg+x75C3TR
-+d4B+CWGkoJqaWEcnHA/CEz25t2bVxLWm5UKuCWoEFuUvNh3tZ4xIMjxJrCPMa7A
-/YTEYTfFPGk0Kod0HKoGIukqFZ6YonzdbQ9R0kPuZKlf+XkrEBd13NmlBbaGTX7e
-/yKeS+LQqOedpJTLqOI+BeytbVVpaN1Ua6c5PfHk6tOdAnA8fHKYT4ZHiKzPTrob
-suqqUYlxnqu08xYDq6mzDtkILTfsLwY3UaS5xghs1VY1twYP5qkhHbrhfXMH7Ndt
-u0EtB/+qOn4cIREDJ9DPSh5BEfLBPe9e9a4FzFm/XkpQfgAOrqsMoItlmej0d8g3
-NwmAeQKCAQBNfiDK0RFQLCKIX+cESdmyj9qKP090x5vfiK3S/SKKy6rvbcrIcUxq
-dIRww4vzk4dDrpQflam6Pc3F389L7aCmbjXsRMz+sEiln154WdTH/I/s9audB3Vt
-A+iso+9X6an2rjeuBJDytA1pCFSEB9udolc9Mqwc5XGr+nYnYaytEIa2y/NJiHF2
-Xvw9Bdn4dVRq2nZ/HRFfMcM/dJzR9aBNn6QtqujFDtLUtbxB82OZEca6LyiTD65i
-ivdb0O6xOnzaqtlQ7eymgj/gloRvYRKUtUA4bOGAkqLiAXZzGyLqpIYewEqn3RRV
-yTViVCsPyD6mYneOf7CSavO+BBEoMKyZAoIBAAF2bGafAIIfxG2wT19Trd6NTFeA
-5GuejnWZBJUJPlIMiwhiorOMOxhJjsfDQxVv/jhWOf86gpLctMIFBHqwIVAwLRVB
-SX0vx6/BUkDsnqEEsyp8x2MKsojvG63QX2R5DJTlP6/YrtVJj46euboygc6j+mV8
-alhiH3UfKKs2GtbIhd34tafRYs9/SvJ95QeoJyVoYy7mLgrFgQN2g2TMwDle/F2h
-kmko+yuLbj5CNe/x4/9pTRTFdoF75RLkaWuf81FHO4c1Z5D5niEX+0a94Y3LglWe
-2YIWhS3TbGPAfyGsnmnTsDtsbriNDwLkmMW7wr6Um+L/LoRVeJhoKxv8LsQ=
------END RSA PRIVATE KEY-----
diff --git a/examples/space_helmet/src/hello.rs b/examples/space_helmet/src/hello.rs
@@ -1,33 +0,0 @@
-#![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,7 +86,7 @@ if [ "$1" = "--contrib" ]; then
tera_templates
handlebars_templates
serve
- space_helmet
+ helmet
diesel_postgres_pool
diesel_sqlite_pool
diesel_mysql_pool