0f19654feat: security headers on every response1d | 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | use topcoat::{ |
| 9 | Result, |
| 10 | context::CxBuilder, |
| 11 | router::{ |
| 12 | Body, HeaderValue, Next, Response, |
| 13 | header::{ |
| 14 | CONTENT_SECURITY_POLICY, REFERRER_POLICY, X_CONTENT_TYPE_OPTIONS, X_FRAME_OPTIONS, |
| 15 | }, |
| 16 | layer, |
| 17 | }, |
| 18 | }; |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | const POLICY: &str = "default-src 'none'; \ |
| 33 | style-src 'self' 'unsafe-inline'; \ |
| 34 | img-src 'self' data:; \ |
| 35 | font-src 'self'; \ |
| 36 | form-action 'self'; \ |
| 37 | frame-ancestors 'none'; \ |
| 38 | base-uri 'none'"; |
| 39 | |
| 40 | #[layer("/")] |
| 41 | async fn security_headers(cx: &mut CxBuilder, body: Body, next: Next<'_>) -> Result<Response> { |
| 42 | let mut response = next.run(cx, body).await?; |
| 43 | let headers = response.headers_mut(); |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | headers |
| 49 | .entry(CONTENT_SECURITY_POLICY) |
| 50 | .or_insert(HeaderValue::from_static(POLICY)); |
| 51 | |
| 52 | headers |
| 53 | .entry(X_CONTENT_TYPE_OPTIONS) |
| 54 | .or_insert(HeaderValue::from_static("nosniff")); |
| 55 | |
| 56 | |
| 57 | |
| 58 | |
| 59 | |
| 60 | headers |
| 61 | .entry(REFERRER_POLICY) |
| 62 | .or_insert(HeaderValue::from_static("no-referrer")); |
| 63 | |
| 64 | |
| 65 | |
| 66 | |
| 67 | headers |
| 68 | .entry(X_FRAME_OPTIONS) |
| 69 | .or_insert(HeaderValue::from_static("DENY")); |
| 70 | |
| 71 | Ok(response) |
| 72 | } |