Skip to content

Commit 147f8aa

Browse files
Merge #597
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.
2 parents 172729a + 3cba145 commit 147f8aa

File tree

9 files changed

+70
-9
lines changed

9 files changed

+70
-9
lines changed

app/styles/app.scss

+8
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,11 @@ h1 {
342342
padding: 5px;
343343
}
344344
}
345+
346+
.arrow-in-list svg {
347+
background: #fff;
348+
}
349+
350+
a.arrow svg {
351+
background: #EEECDD;
352+
}

app/templates/components/category-list.hbs

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
<li>
44
{{#link-to 'category' category.slug class='name'}}
55
<span>{{ category.category }} ({{ format-num category.crates_cnt }})</span>
6-
{{svg-jar "right-arrow"}}
6+
<div class='arrow-in-list'>
7+
{{svg-jar "right-arrow"}}
8+
</div>
79
{{/link-to}}
810
</li>
911
{{/each}}

app/templates/components/crate-list.hbs

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
<li>
44
{{#link-to 'crate' crate.id class='name'}}
55
<span>{{ crate.name }} ({{ crate.max_version }})</span>
6-
{{svg-jar "right-arrow"}}
6+
<div class='arrow-in-list'>
7+
{{svg-jar "right-arrow"}}
8+
</div>
79
{{/link-to}}
810
</li>
911
{{/each}}

app/templates/components/keyword-list.hbs

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
<li>
44
{{#link-to 'keyword' keyword class='name'}}
55
<span>{{ keyword.id }} ({{ format-num keyword.crates_cnt }})</span>
6-
{{svg-jar "right-arrow"}}
6+
<div class='arrow-in-list'>
7+
{{svg-jar "right-arrow"}}
8+
</div>
79
{{/link-to}}
810
</li>
911
{{/each}}

app/templates/crate/version.hbs

-3
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@
4040
</div>
4141
</div>
4242

43-
{{! This is used to set the url of to actually download a file }}
44-
<iframe id='download-frame' style='display:none'></iframe>
45-
4643
{{#if currentVersion.yanked}}
4744
<div class='crate-info'>
4845
<div>

app/templates/crate/versions.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
{{/if}}
2323
</div>
2424
{{#link-to 'crate.version' version.num class='arrow'}}
25-
{{svg-jar "right-arrow" style="background-color: #EEECDD"}}
25+
{{svg-jar "right-arrow"}}
2626
{{/link-to}}
2727
</div>
2828
{{/each}}

public/assets/right-arrow.svg

+1-1
Loading

src/http.rs

+48-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use conduit::{Request, Response};
2+
use conduit_middleware::Middleware;
13
use curl;
24
use curl::easy::{Easy, List};
35
use oauth2::*;
@@ -6,7 +8,7 @@ use util::{CargoResult, internal, ChainError, human};
68
use serde_json;
79
use serde::Deserialize;
810
use std::str;
9-
11+
use std::error::Error;
1012

1113
/// Does all the nonsense for sending a GET to Github. Doesn't handle parsing
1214
/// because custom error-code handling may be desirable. Use
@@ -88,3 +90,48 @@ pub fn token(token: String) -> Token {
8890
token_type: String::new(),
8991
}
9092
}
93+
94+
#[derive(Clone, Copy, Debug)]
95+
pub struct SecurityHeadersMiddleware;
96+
97+
impl Middleware for SecurityHeadersMiddleware {
98+
fn after(
99+
&self,
100+
_: &mut Request,
101+
mut res: Result<Response, Box<Error + Send>>,
102+
) -> Result<Response, Box<Error + Send>> {
103+
if let Ok(ref mut response) = res {
104+
// It would be better if we didn't have to have 'unsafe-eval' in the `script-src`
105+
// policy, but google charts (used for the download graph on crate pages) uses `eval`
106+
// to load scripts. Remove 'unsafe-eval' if google fixes the issue:
107+
// https://github.com/google/google-visualization-issues/issues/1356
108+
// or if we switch to a different graph generation library.
109+
response.headers.insert(
110+
"Content-Security-Policy".into(),
111+
vec![
112+
"default-src 'self'; \
113+
connect-src 'self' https://docs.rs; \
114+
script-src 'self' 'unsafe-eval' \
115+
https://www.google-analytics.com https://www.google.com; \
116+
style-src 'self' https://www.google.com https://ajax.googleapis.com; \
117+
img-src *; \
118+
object-src 'none'"
119+
.into(),
120+
],
121+
);
122+
response.headers.insert(
123+
"X-Content-Type-Options".into(),
124+
vec!["nosniff".into()],
125+
);
126+
response.headers.insert(
127+
"X-Frame-Options".into(),
128+
vec!["SAMEORIGIN".into()],
129+
);
130+
response.headers.insert(
131+
"X-XSS-Protection".into(),
132+
vec!["1; mode=block".into()],
133+
);
134+
}
135+
res
136+
}
137+
}

src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ pub fn middleware(app: Arc<App>) -> MiddlewareBuilder {
227227
cookie::Key::from_master(app.session_key.as_bytes()),
228228
env == Env::Production,
229229
));
230+
if env == Env::Production {
231+
m.add(http::SecurityHeadersMiddleware);
232+
}
230233
m.add(app::AppMiddleware::new(app));
231234

232235
// Run each request in a transaction and roll back the transaction if the request results

0 commit comments

Comments
 (0)