Rocket icon indicating copy to clipboard operation
Rocket copied to clipboard

Native support for Content-Security-Policy

Open BernhardPosselt opened this issue 8 years ago • 3 comments

Similar to https://github.com/SergioBenitez/Rocket/issues/25 there should be an easy way to configure a CSP. CSP is a way to make XSS almost impossible and is easy and straight forward to configure.

I'm using both CORS and CSP in a Django project and every time a new Django version is released, it's a huge pain to wait for all the necessary extensions to support the current version. In addition to that adding CSP should be pretty straight forward:

  • Create a datatype which exposes all the relevant fields listed here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
  • Each field could hold a list of strings (maybe add string constants for 'self' and other values)
  • Create a serializer for the object

It should be possible to define different CSP policies for different routes (e.g. register user pages may want to include RECaptcha which needs certain CSP exemptions)

Reasons to not include CSP for me would be:

  • The standard seems to evolve quickly, 1.0 was released in 2015, 2.0 was released in 2016, 3.0 is currently in draft
  • It could be challenging to create a secure default policy which is backwards compatible (we had issues with that in Nextcloud)
  • CSP data structure and serialization could be implemented in a framework agnostic way

Reasons to include a CSP implementation in Rocket for me would be:

  • There can be one implementation which fits all usecases (compared to templates and databases where you want people to choose their own platform)
  • Implementation should be straight forward
  • I doubt that it will produce a lot of code. The resulting code should be easy to maintain and test.
  • Outsourcing it into a separate library will make it harder for users to upgrade to newer Rocket versions if Rocket deprecates or removes functionality (this is currently the case with Django)
  • Security is hard to get right on your own
  • CSP should be implemented in a typesafe way since typos might make your application vulernable to XSS attacks
  • IE needs special treatment (header is called X-Content-Security-Policy)
  • Personally I wouldn't know how to implement it in Rocket
  • It is (at least for me) an autoinclude in every web project

BernhardPosselt avatar Apr 17 '17 18:04 BernhardPosselt

This is something that I've spent some time thinking about because we offer functionality like it in one of our products. Currently the way that we handle it is by forcing the user to enter the fully created string and it's just added to all responses. As you're probably thinking, this is a really bad way to do it. Generating CSP headers can be extremely difficult if your application is complex and pull resources for many places and it's incredibly easy to screw up. Something we've talked about doing a creating a GUI tool for configuring it and ideally putting it into a format that the tool can read and then generate a string or create a serializer that goes both ways. One other thing to keep in mind is that it's probably a good idea to store a cached version of the generated header once it's been generated once since this will be added to all responses leaving the server and computing it each time could be expensive.

jrozner avatar May 04 '17 07:05 jrozner

There is a pretty good documentation at https://wiki.mozilla.org/Security/Guidelines/Web_Security#Content_Security_Policy including some candidates for default CSPs. From an implementation point of view, it looks like a Fairing could be used to attach CSPs to paths. I agree with everything about the difficulty to create and manage good CSPs ;)

fabricedesre avatar May 31 '17 21:05 fabricedesre

Hi there,

I took out rocket.rs for a trial run this weekend:

  • used the default rocket.rs 0.4(Sync version NOT MASTER ASYNC VERSION),
  • improvised the example/static_files
  • tweaked example/static_files to become tls

Then I let ssllabs and webpagetest have a go at https://davidmarceau.tk

https://www.ssllabs.com/ssltest/analyze.html?d=davidmarceau.tk

  • Reported: A but potentially could give A+

https://www.webpagetest.org/result/210412_AiDcGM_8314e8be0968b1d3f888f9aa862e7391/

  • Security score - A
  • First Byte Time - A
  • Keep-alive Enabled - A
  • Compress Transfer - A
  • Compress Images - N/A (I had none)
  • Cache static content - D (I didn't)
  • Effective use of CDN - X (I didn't)

I didn't get A+ on ssllabs because content security policy(csp) is missing.

In the webpagetest security score, if you click on it, it says: " Missing Content Security Policy. A computer security standard introduced to prevent cross-site scripting (XSS), clickjacking and other code injection attacks resulting from execution of malicious content in the trusted web page context."

As a user taking out golang-based caddy for a test run, I can achieve A+ from ssllabs in no time flat, but I would have enjoyed being able to use helmet csp defaults to achieve the same thing with rocket.rs. I really think the proposed helmet csp would have been preferrable to no csp. It would help rocket.rs reach better security scores on ssllabs/webpagetest and attain even more popularity for rocket.rs' ease of use. I do hope you'll reconsider.

Also I tried unsuccessfully to use: https://securitytxt.org/ By making available as static files:

  • security.txt
  • security-policy.txt
$ cat security.txt 
Contact: mailto:[email protected]
Expires: Wed, 30 Jun 2010 23:58 -0400
Preferred-Languages: en
Canonical: https://davidmarceau.tk/security.txt
Policy: https://davidmarceau.tk/security-policy.txt

$ cat security-policy.txt 
Content-Security-Policy: default-src https:
Content-Security-Policy: default-src *; object-src 'none'
Content-Security-Policy: default-src 'self'; img-src 'self' object-src 'none'
Content-Security-Policy: default-src 'none'; font-src 'self'; img-src 'self'; object-src 'none'; script-src 'self'; style-src 'self'
Content-Security-Policy: default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'

Get a free domain name from freenom https://my.freenom.com

Get a free ssl cert from zerossl.com https://app.zerossl.com/

zerosslCerts11April2021/ca_bundle.crt
zerosslCerts11April2021/certificate.crt
zerosslCerts11April2021/private.key
cat zerosslCerts11April2021/certificate.crt zerosslCerts11April2021/ca_bundle.crt > zerosslCerts11April2021/rocketrsFullChain11April2021.crt

Then tweak the Rocket.toml to point to that private.key and full chain:

$ cat Rocket.toml
[global.tls]
certs = "zerosslCerts11April2021/rocketrsFullChain11April2021.crt"
key = "zerosslCerts11April2021/private.key"
cat Cargo.toml
[package]
name = "davidmarceau_tk_static"
version = "0.0.0"
workspace = "../../"
publish = false

[dependencies]
rocket = { path = "../../core/lib", features = ["tls"] }
rocket_contrib = { path = "../../contrib/lib", features = ["helmet"] }
cat main.rs
extern crate rocket;
extern crate rocket_contrib;

#[cfg(test)] mod tests;
use rocket::http::uri::Uri;
use rocket_contrib::helmet::SpaceHelmet;
use rocket_contrib::helmet::Frame;
use rocket_contrib::helmet::XssFilter;
use rocket_contrib::helmet::Hsts;
use rocket_contrib::serve::StaticFiles;

fn rocket() -> rocket::Rocket {
    let site_uri = Uri::parse("https://davidmarceau.tk").unwrap();
    rocket::ignite().attach(
        rocket_contrib::helmet::SpaceHelmet::default()
            .enable(Hsts::default())
            .enable(XssFilter::Enable)
            .enable(Frame::AllowFrom(site_uri))
            ).mount("/", StaticFiles::from("static"))
}

fn main() {
    rocket().launch();
}

I hope the above helps other get an A for a security score at least, but yes if you could add that helmet csp, we could all get A+ security scores :)

Thank you for listening.

omac777 avatar Apr 12 '21 12:04 omac777