about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2025-01-02 06:37:04 +0300
committerVika <vika@fireburn.ru>2025-01-02 06:37:04 +0300
commit78f8de236b7ab9755f0212a740d341a2518968da (patch)
tree7cadf22493c9f25e4b9043321de765547375f49f
parentd10710326da703f69eaa06723dc66e330fd32745 (diff)
downloadkittybox-78f8de236b7ab9755f0212a740d341a2518968da.tar.zst
Set X-Content-Type-Options: nosniff
This prevents browsers from guessing the Content-Type, and since we're
always making sure to serve with the known-correct content type, we
don't need the browser to guess.

Change-Id: I02550d6763969f999ec22ec41e5539f945ea7ca4
-rw-r--r--src/frontend/mod.rs8
-rw-r--r--src/media/mod.rs4
-rw-r--r--templates/src/lib.rs18
3 files changed, 24 insertions, 6 deletions
diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs
index 8338ac6..9ba1a69 100644
--- a/src/frontend/mod.rs
+++ b/src/frontend/mod.rs
@@ -250,6 +250,10 @@ pub async fn homepage<D: Storage>(
         axum::http::header::CONTENT_TYPE,
         axum::http::HeaderValue::from_static(r#"text/html; charset="utf-8""#),
     );
+    headers.insert(
+        axum::http::header::X_CONTENT_TYPE_OPTIONS,
+        axum::http::HeaderValue::from_static("nosniff")
+    );
 
     let user = session.as_deref().map(|s| &s.me);
     match tokio::try_join!(
@@ -365,6 +369,10 @@ pub async fn catchall<D: Storage>(
                 axum::http::header::CONTENT_TYPE,
                 axum::http::HeaderValue::from_static(r#"text/html; charset="utf-8""#),
             );
+            headers.insert(
+                axum::http::header::X_CONTENT_TYPE_OPTIONS,
+                axum::http::HeaderValue::from_static("nosniff")
+            );
             if user.is_some() {
                 headers.insert(
                     axum::http::header::CACHE_CONTROL,
diff --git a/src/media/mod.rs b/src/media/mod.rs
index 199f05f..6f263b6 100644
--- a/src/media/mod.rs
+++ b/src/media/mod.rs
@@ -103,6 +103,10 @@ pub(crate) async fn serve<S: MediaStore>(
                             .unwrap_or("application/octet-stream")
                     ).unwrap()
                 );
+                headers.insert(
+                    axum::http::header::X_CONTENT_TYPE_OPTIONS,
+                    axum::http::HeaderValue::from_static("nosniff")
+                );
                 if let Some(length) = metadata.length {
                     headers.typed_insert(ContentLength(length.get().try_into().unwrap()));
                 }
diff --git a/templates/src/lib.rs b/templates/src/lib.rs
index 96bf592..d9fe86b 100644
--- a/templates/src/lib.rs
+++ b/templates/src/lib.rs
@@ -15,7 +15,7 @@ pub mod assets {
     use axum::response::{IntoResponse, Response};
     use axum::extract::Path;
     use axum::http::StatusCode;
-    use axum::http::header::{CONTENT_TYPE, CONTENT_ENCODING, CACHE_CONTROL};
+    use axum::http::header::{CONTENT_TYPE, CONTENT_ENCODING, CACHE_CONTROL, X_CONTENT_TYPE_OPTIONS};
 
     const ASSETS: include_dir::Dir<'static> = include_dir::include_dir!("$OUT_DIR/");
     const CACHE_FOR_A_DAY: &str = "max-age=86400";
@@ -36,14 +36,20 @@ pub mod assets {
 
         match ASSETS.get_file(path.clone() + ".gz") {
             Some(file) => (StatusCode::OK,
-                           [(CONTENT_TYPE, content_type),
-                            (CONTENT_ENCODING, GZIP),
-                            (CACHE_CONTROL, CACHE_FOR_A_DAY)],
+                           [
+                               (CONTENT_TYPE, content_type),
+                               (CONTENT_ENCODING, GZIP),
+                               (CACHE_CONTROL, CACHE_FOR_A_DAY),
+                               (X_CONTENT_TYPE_OPTIONS, "nosniff")
+                           ],
                            file.contents()).into_response(),
             None => match ASSETS.get_file(path) {
                 Some(file) => (StatusCode::OK,
-                               [(CONTENT_TYPE, content_type),
-                                (CACHE_CONTROL, CACHE_FOR_A_DAY)],
+                               [
+                                   (CONTENT_TYPE, content_type),
+                                   (CACHE_CONTROL, CACHE_FOR_A_DAY),
+                                   (X_CONTENT_TYPE_OPTIONS, "nosniff")
+                               ],
                                file.contents()).into_response(),
                 None => StatusCode::NOT_FOUND.into_response()
             }