From 6230c23566adaff4b74ce4ec9b572dba39adc569 Mon Sep 17 00:00:00 2001 From: Marius Date: Mon, 19 Feb 2018 18:28:42 +0100 Subject: [PATCH] Force browser to download content For example, prevent HTML from being rendered --- get_test.go | 8 +++----- unrouted_handler.go | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/get_test.go b/get_test.go index c8047bc..7739fb1 100644 --- a/get_test.go +++ b/get_test.go @@ -56,7 +56,8 @@ func TestGet(t *testing.T) { URL: "yes", ResHeader: map[string]string{ "Content-Length": "5", - "Content-Disposition": `inline;filename="file.jpg\"evil"`, + "Content-Type": "application/octet-stream", + "Content-Disposition": `attachment;filename="file.jpg\"evil"`, }, Code: http.StatusOK, ResBody: "hello", @@ -70,9 +71,6 @@ func TestGet(t *testing.T) { SubTest(t, "EmptyDownload", func(t *testing.T, store *MockFullDataStore) { store.EXPECT().GetInfo("yes").Return(FileInfo{ Offset: 0, - MetaData: map[string]string{ - "filename": "file.jpg\"evil", - }, }, nil) handler, _ := NewHandler(Config{ @@ -84,7 +82,7 @@ func TestGet(t *testing.T) { URL: "yes", ResHeader: map[string]string{ "Content-Length": "0", - "Content-Disposition": `inline;filename="file.jpg\"evil"`, + "Content-Disposition": `attachment`, }, Code: http.StatusNoContent, ResBody: "", diff --git a/unrouted_handler.go b/unrouted_handler.go index 2285e58..8c6e286 100644 --- a/unrouted_handler.go +++ b/unrouted_handler.go @@ -542,17 +542,26 @@ func (handler *UnroutedHandler) GetFile(w http.ResponseWriter, r *http.Request) // Set headers before sending responses w.Header().Set("Content-Length", strconv.FormatInt(info.Offset, 10)) + w.Header().Set("Content-Type", "application/octet-stream") + + // Force browsers to download the file instead of displaying it inline. + // Otherwise someone could upload malicious HTML which would then be + // executed if a victim visits this URL. + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition + // TODO: Consider lifting this limitation and allow e.g. images to be shown + // TODO: Consider pulling Content-Type from meta data if filename, ok := info.MetaData["filename"]; ok { - w.Header().Set("Content-Disposition", "inline;filename="+strconv.Quote(filename)) + w.Header().Set("Content-Disposition", "attachment;filename="+strconv.Quote(filename)) + } else { + w.Header().Set("Content-Disposition", "attachment") } - // Do not do anything if no data is stored yet. + // If no data has been uploaded yet, respond with an empty "204 No Content" status. if info.Offset == 0 { handler.sendResp(w, r, http.StatusNoContent) return } - // Get reader src, err := handler.composer.GetReader.GetReader(id) if err != nil { handler.sendError(w, r, err)