Commit 531110f9 authored by Jérome Perrin's avatar Jérome Perrin

fixup! NXD xblob: don't let net/http sniff content type

support rendering svg as images, while still applying a CSP and forcing
download to prevent executing javascript they may contain
parent 82b9d05a
...@@ -11,10 +11,12 @@ import ( ...@@ -11,10 +11,12 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"mime"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"os/exec" "os/exec"
"path"
"regexp" "regexp"
"strings" "strings"
"syscall" "syscall"
...@@ -179,7 +181,6 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string, r *http.Re ...@@ -179,7 +181,6 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string, r *http.Re
} }
// Blob found - start writing response // Blob found - start writing response
w.Header().Set("Content-Disposition", "inline")
w.Header().Set("Content-Transfer-Encoding", "binary") w.Header().Set("Content-Transfer-Encoding", "binary")
w.Header().Set("Content-Length", fmt.Sprintf("%d", size)) w.Header().Set("Content-Length", fmt.Sprintf("%d", size))
w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-Content-Type-Options", "nosniff")
...@@ -204,12 +205,22 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string, r *http.Re ...@@ -204,12 +205,22 @@ func emitBlob(w http.ResponseWriter, repopath string, refpath string, r *http.Re
// accessed from the /blob/ view. // accessed from the /blob/ view.
// See https://gitlab.com/gitlab-org/gitlab-foss/-/blob/77c7b561/app/helpers/blob_helper.rb#L138-144 // See https://gitlab.com/gitlab-org/gitlab-foss/-/blob/77c7b561/app/helpers/blob_helper.rb#L138-144
contentType := http.DetectContentType(buffer) contentType := http.DetectContentType(buffer)
if strings.HasPrefix(contentType, "text/") { if mime.TypeByExtension(path.Ext(refpath)) == "image/svg+xml" {
// Serve SVG with a content securtiy policy to prevent execution of inline javascript
// note that the detection is a bit more complex
// https://github.com/golang/go/issues/15888#issuecomment-222457018
w.Header().Set("Content-Type", "image/svg+xml; charset=utf-8")
w.Header().Set("Content-Disposition", "attachment")
w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
} else if strings.HasPrefix(contentType, "text/") {
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("Content-Disposition", "inline")
} else if strings.HasPrefix(contentType, "image/") { } else if strings.HasPrefix(contentType, "image/") {
w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Type", contentType)
w.Header().Set("Content-Disposition", "inline")
} else { } else {
w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment")
} }
w.WriteHeader(http.StatusOK) // Don't bother with HTTP 500 from this point on, just return w.WriteHeader(http.StatusOK) // Don't bother with HTTP 500 from this point on, just return
w.Write(buffer) w.Write(buffer)
......
...@@ -707,9 +707,10 @@ func TestBlobDownload(t *testing.T) { ...@@ -707,9 +707,10 @@ func TestBlobDownload(t *testing.T) {
dl.ExpectHeader("/5f923865/files/js/application.js", "content-type", "text/plain; charset=utf-8") dl.ExpectHeader("/5f923865/files/js/application.js", "content-type", "text/plain; charset=utf-8")
dl.ExpectHeader("/5f923865/files/images/logo-white.png", "content-type", "image/png") dl.ExpectHeader("/5f923865/files/images/logo-white.png", "content-type", "image/png")
dl.ExpectHeader("/5f923865/files/images/6049019_460s.jpg", "content-type", "image/jpeg") dl.ExpectHeader("/5f923865/files/images/6049019_460s.jpg", "content-type", "image/jpeg")
dl.ExpectHeader("/5f923865/files/images/wm.svg", "content-type", "text/plain; charset=utf-8") dl.ExpectHeader("/5f923865/files/images/wm.svg", "content-type", "image/svg+xml; charset=utf-8")
dl.ExpectHeader("/5f923865/files/images/wm.svg", "content-disposition", "attachment")
dl.ExpectHeader("/5f923865/files/images/wm.svg", "content-security-policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
dl.ExpectHeader("/5f923865/Gemfile.zip", "content-type", "application/octet-stream") dl.ExpectHeader("/5f923865/Gemfile.zip", "content-type", "application/octet-stream")
dl.ExpectHeader("/5f923865/files/images/wm.svg", "content-type", "text/plain; charset=utf-8")
dl.ExpectHeader("/5f923865/VERSION", "content-type", "text/plain; charset=utf-8") dl.ExpectHeader("/5f923865/VERSION", "content-type", "text/plain; charset=utf-8")
// empty file // empty file
dl.ExpectHeader("/5f923865/files/flat/path/correct/content.txt", "content-type", "text/plain; charset=utf-8") dl.ExpectHeader("/5f923865/files/flat/path/correct/content.txt", "content-type", "text/plain; charset=utf-8")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment