Browse Source

Allow images with data URLs

Only URLs with a mime-type image/* are allowed
Frédéric Guillot 5 years ago
parent
commit
864dd9f219

+ 1 - 1
http/response/builder.go

@@ -96,7 +96,7 @@ func (b *Builder) writeHeaders() {
 	b.headers["X-XSS-Protection"] = "1; mode=block"
 	b.headers["X-Content-Type-Options"] = "nosniff"
 	b.headers["X-Frame-Options"] = "DENY"
-	b.headers["Content-Security-Policy"] = "default-src 'self'; img-src *; media-src *; frame-src *"
+	b.headers["Content-Security-Policy"] = "default-src 'self'; img-src * data:; media-src *; frame-src *"
 
 	for key, value := range b.headers {
 		b.w.Header().Set(key, value)

+ 1 - 1
http/response/builder_test.go

@@ -32,7 +32,7 @@ func TestResponseHasCommonHeaders(t *testing.T) {
 		"X-XSS-Protection":        "1; mode=block",
 		"X-Content-Type-Options":  "nosniff",
 		"X-Frame-Options":         "DENY",
-		"Content-Security-Policy": "default-src 'self'; img-src *; media-src *; frame-src *",
+		"Content-Security-Policy": "default-src 'self'; img-src * data:; media-src *; frame-src *",
 	}
 
 	for header, expected := range headers {

+ 22 - 1
reader/sanitizer/sanitizer.go

@@ -111,7 +111,7 @@ func sanitizeAttributes(baseURL, tagName string, attributes []html.Attribute) ([
 				} else {
 					continue
 				}
-			} else if tagName == "img" && attribute.Key == "src" && strings.HasPrefix(attribute.Val, "data:") {
+			} else if tagName == "img" && attribute.Key == "src" && isValidDataAttribute(attribute.Val) {
 				value = attribute.Val
 			} else {
 				value, err = url.AbsoluteURL(baseURL, value)
@@ -480,3 +480,24 @@ func isValidWidthOrDensityDescriptor(value string) bool {
 	_, err := strconv.ParseFloat(value[0:len(value)-1], 32)
 	return err == nil
 }
+
+func isValidDataAttribute(value string) bool {
+	var dataAttributeAllowList = []string{
+		"data:image/avif",
+		"data:image/apng",
+		"data:image/png",
+		"data:image/svg",
+		"data:image/svg+xml",
+		"data:image/jpg",
+		"data:image/jpeg",
+		"data:image/gif",
+		"data:image/webp",
+	}
+
+	for _, prefix := range dataAttributeAllowList {
+		if strings.HasPrefix(value, prefix) {
+			return true
+		}
+	}
+	return false
+}

+ 10 - 0
reader/sanitizer/sanitizer_test.go

@@ -15,6 +15,16 @@ func TestValidInput(t *testing.T) {
 	}
 }
 
+func TestImgWithTextDataURL(t *testing.T) {
+	input := `<img src="data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==" alt="Example">`
+	expected := ``
+	output := Sanitize("http://example.org/", input)
+
+	if output != expected {
+		t.Errorf(`Wrong output: %s`, output)
+	}
+}
+
 func TestImgWithDataURL(t *testing.T) {
 	input := `<img src="data:image/gif;base64,test" alt="Example">`
 	expected := `<img src="data:image/gif;base64,test" alt="Example" loading="lazy">`