-
Notifications
You must be signed in to change notification settings - Fork 610
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add security headers #597
Add security headers #597
Conversation
I have this up on staging now, the deploy went fine, the observatory now gives staging an A+, installing a crate via cargo from staging worked fine. Anything else we should check? |
Not that I can think of. |
Actually I'm seeing a console error when I run it locally. We have an inline script tag from google analytics that I guess we need to fix. |
👍 Looks good. Putting the inline script in its own file with the async ga analytics.js should workaround the error. diff --git a/app/index.html b/app/index.html
index 3de7338..a4ebf8c 100644
--- a/app/index.html
+++ b/app/index.html
@@ -7,15 +7,8 @@
{{content-for 'head'}}
- <script>
- (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
- (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
- m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
- })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
-
- ga('create', 'UA-58390457-3', 'auto');
- ga('send', 'pageview');
- </script>
+ <script src="{{rootURL}}assets/ga-pageview.js"></script>
+ <script async src="https://www.google-analytics.com/analytics.js"></script>
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
<link rel="stylesheet" href="{{rootURL}}assets/cargo.css">
diff --git a/dist/assets/ga-pageview.js b/dist/assets/ga-pageview.js
new file mode 100644
index 0000000..68f8501
--- /dev/null
+++ b/dist/assets/ga-pageview.js
@@ -0,0 +1,3 @@
+window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
+ga('create', 'UA-58390457-3', 'auto');
+ga('send', 'pageview'); |
Just a note that you should be careful with You might want to make this one opt-in, unless this is really not a concern. This should not be taken as being against HSTS - |
I don't feel like I have enough knowledge in this area to make this call :-/ I'll try to do some research around this soon. |
@sgrif are you up for making this suggested change to handle the GA script in the meantime though? |
+1 on rolling out HSTS slowly as mentioned here. I don't remember the exact value, but services usually start with a low HSTS max-age (minutes) and make sure everything keeps working for awhile before bumping it to a year (like DNS changes). |
What's the status on this pull request? What needs to be done to unblock this? |
I think the ember folks changed google analytics recently, I'm not sure if it's now async or not or whatever we need google analytics to be-- that needs to be researched and changed and tested if necessary. I need to read up on HSTS and understand the implications before deploying-- that's unfortunately not something you can unblock for me :) |
Ok reading a bit about HSTS on these sites: it sounds like until we get https://doc.crates.io working (see #621), we definitely should NOT be sending
Indeed it is! Running this:
shows this in the response headers:
Looks like this is happening because we use the nginx buildpack and we've specified that in config/nginx.conf.erb. People deploying crates.io on their own servers may not be using that file at all, and if they do, they can choose to remove or change that line. So I don't think we need to be setting the STS headers in the spot that this PR does. HOWEVER, mozilla observatory is not seeing this. In their "raw server headers", I see "Content-Type | application/json; charset=utf-8", which means they're not requesting a content type, and crates.io defaults to JSON which returns a 404 for /:
Soo it looks like we need to solve #163 before we can get the observatory to see that :-/ |
src/http.rs
Outdated
); | ||
response.headers.insert( | ||
"Strict-Transport-Security".into(), | ||
vec!["max-age=31536000; includeSubDomains".into()], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming that #895 is merged, this should be removed. This should probably be configured further up the stack anyway since mirrors could be deployed over HTTP.
If we want to continue setting the header here then as mentioned by @carols10cents includeSubdomains
should be removed.
src/lib.rs
Outdated
@@ -150,6 +150,9 @@ pub fn middleware(app: Arc<App>) -> MiddlewareBuilder { | |||
m.add(conduit_cookie::Middleware::new(app.session_key.as_bytes())); | |||
m.add(conduit_cookie::SessionMiddleware::new("cargo_session", | |||
env == Env::Production)); | |||
if env == Env::Production { | |||
m.add(http::SecurityHeadersMiddleware); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its unclear to me exactly what the order of middleware layers will be. Lower in the file dist::Middleware
is added with around
so I think that static files will be served without these headers. In particular, that would include index.html
. The security middleware should probably be the outermost middleware if it isn't already.
URLs matching ^/assets/
will be served directly by nginx, but static files in the root (such as index.html
and robots.txt
) are served through this static dist
middleware. I have no idea if any of these headers should also be applied to static assets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these headers were picked up when this was deployed on staging it looks like the middleware layers are stacked in the correct order.
Given that in production most static assets are served directly from nginx, I think X-Content-Type-Options: nosniff
should also be included in nginx.conf.erb
. Looking over the other headers, I don't think any of the rest apply to such assets (except HSTS).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just going through the PRs to get documentation comments added for new types :)
src/http.rs
Outdated
@@ -76,3 +78,38 @@ pub fn token(token: String) -> Token { | |||
token_type: String::new(), | |||
} | |||
} | |||
|
|||
pub struct SecurityHeadersMiddleware; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add a documentation comment here?
895: Enable HSTS headers on all responses r=carols10cents **Deployment Warning:** This pull request uses a configuration syntax added in nginx-1.7.5 and requires switching to a new buildpack. ~~If this pull request is merged the buildpack configuration on *staging* and *production* will need to be changed on Heroku.~~ (This is no longer a concern with the updated PR as this is specified in `.buildpacks`.) It is unclear if there are any existing mirror deployments on Heroku or otherwise depending on our `nginx.conf.erb` template. This pull request enables HSTS headers for all responses. My tests show an upgrade from an F to a D on the Mozilla Observatory. (Out of 100 points, this scores 35 instead of 15.) Please also see the discussion in #597 which is what prompted my review. This pull request also fixes the buildpack URLs defined in `app.json` so that the Heroku deploy button works. # Nginx buildpack upgrade The previous buildpack was based on nginx-1.5.7 which was released in November of 2013. Fortunately for us, it looks like travis-ci recently cloned this buildpack and upgraded it to the latest release of 1.13.3. Note that the odd minor version number represents that this (as well as our previous release) is from the development branch. The stable release of 1.12.1 may be preferable, but I expect that the travis-ci clone is our best bet for a responsive upstream at this time. # Nginx configuration change Two changes to the nginx configuration file where necessary. See http://nginx.org/en/docs/http/ngx_http_headers_module.html for more details on both of these. ## Use the always parameter The `always` parameter was introduced in nginx-1.7.5. The HSTS header is now included for all response codes. ## Duplicate header declaration in both blocks This surprised me, but the documentation states: > There could be several add_header directives. These directives are inherited from the previous level **if and only if** there are no add_header directives defined on the current level. I figured it was best to explicitly duplicate the declaration rather than rely on inheritance at all. # Fix the Deploy to Heroku button This pull request also fixes the Deploy to Heroku button in `docs/MIRROR.md` by updating the `app.json` file. ~~It appears that Heroku does not support URLs with the #SHA fragment. If we want to fix ourselves to specific commits for the buildpacks it may be possible to do so with `archive/*.tar.gz` links, but I suspect that we are currently targeting the master branches for these in production anyway.~~ The PR now sets up `app.json` to use heroku-buildpack-multi which will pull in the other buildpacks from `.buildpacks`. New mirror deployments should now match our staging and production environments.
These headers are all pretty straightforward except CSP. For CSP I defined the sources based on what was loaded from visiting the main page and all crates. Images should be safe, so I've allowed them from all sources. This should be checked on staging before deploying. Fixes rust-lang#586.
013eb66
to
ed3d856
Compare
More stuff that goes with 1aecb45.
Ok. I poked at this a bit more, it's up on https://staging-crates-io.herokuapp.com right now and gets an A+. There were some content security policy violations, but not from google analytics:
The only problem I still see and haven't figured out yet is that the google chart on crate pages (ex: https://staging-crates-io.herokuapp.com/crates/blah-types) isn't working because google's stuff uses I tried upgrading to the "new" way of loading google charts because this comment claimed the "current" version (in march) didn't use I guess some headers are better than none? Idk. I'm sleepy and out of ideas. |
Always leave a note.
Adding |
@kureuil says this works in Edge (thank you!!!), so let's do this. bors: r+ |
@carols10cents I couldn't find anything about the FF Nightly warning, but everything seems to be working perfectly though :) |
597: Add security headers r=carols10cents These headers are all pretty straightforward except CSP. For CSP I defined the sources based on what was loaded from visiting the main page and all crates. Images should be safe, so I've allowed them from all sources. This should be checked on staging before deploying. Fixes #586.
Build succeeded |
script-src 'self' 'unsafe-eval' \ | ||
https://www.google-analytics.com https://www.google.com; \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upstream issue seems fixed, is this still needed?
These headers are all pretty straightforward except CSP. For CSP I
defined the sources based on what was loaded from visiting the main page
and all crates. Images should be safe, so I've allowed them from all
sources.
This should be checked on staging before deploying.
Fixes #586.