content-type checking

This commit is contained in:
Christopher Brown 2018-02-09 15:50:57 -06:00 committed by Will Norris
parent 74c16f575e
commit 39a4e1813d
3 changed files with 82 additions and 6 deletions

View file

@ -26,8 +26,10 @@ import (
"io"
"io/ioutil"
"log"
"mime"
"net/http"
"net/url"
"path/filepath"
"strings"
"time"
@ -67,6 +69,10 @@ type Proxy struct {
// If true, log additional debug messages
Verbose bool
// ContentTypes specifies a list of content types to allow. An empty list means only image types
// are allowed.
ContentTypes []string
}
// NewProxy constructs a new proxy. The provided http RoundTripper will be
@ -162,7 +168,15 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) {
return
}
copyHeader(w.Header(), resp.Header, "Content-Length", "Content-Type")
contentType, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if !validContentType(p.ContentTypes, contentType) {
http.Error(w, "forbidden content-type", http.StatusForbidden)
return
}
w.Header().Set("Content-Type", contentType)
w.Header().Set("X-Content-Type-Options", "nosniff")
copyHeader(w.Header(), resp.Header, "Content-Length")
//Enable CORS for 3rd party applications
w.Header().Set("Access-Control-Allow-Origin", "*")
@ -211,6 +225,36 @@ func (p *Proxy) allowed(r *Request) error {
return fmt.Errorf("request does not contain an allowed host or valid signature: %v", r)
}
// validContentType returns whether contentType matches one of the patterns. If no patterns are
// given, validContentType returns true if contentType matches one of the whitelisted image types.
func validContentType(patterns []string, contentType string) bool {
if len(patterns) == 0 {
switch contentType {
case "image/bmp", "image/cgm", "image/g3fax", "image/gif", "image/ief", "image/jp2",
"image/jpeg", "image/jpg", "image/pict", "image/png", "image/prs.btif", "image/svg+xml",
"image/tiff", "image/vnd.adobe.photoshop", "image/vnd.djvu", "image/vnd.dwg",
"image/vnd.dxf", "image/vnd.fastbidsheet", "image/vnd.fpx", "image/vnd.fst",
"image/vnd.fujixerox.edmics-mmr", "image/vnd.fujixerox.edmics-rlc",
"image/vnd.microsoft.icon", "image/vnd.ms-modi", "image/vnd.net-fpx", "image/vnd.wap.wbmp",
"image/vnd.xiff", "image/webp", "image/x-cmu-raster", "image/x-cmx", "image/x-icon",
"image/x-macpaint", "image/x-pcx", "image/x-pict", "image/x-portable-anymap",
"image/x-portable-bitmap", "image/x-portable-graymap", "image/x-portable-pixmap",
"image/x-quicktime", "image/x-rgb", "image/x-xbitmap", "image/x-xpixmap",
"image/x-xwindowdump":
return true
}
return false
}
for _, pattern := range patterns {
if ok, err := filepath.Match(pattern, contentType); ok && err == nil {
return true
}
}
return false
}
// validHost returns whether the host in u matches one of hosts.
func validHost(hosts []string, u *url.URL) bool {
for _, host := range hosts {