Merge pull request #59 from mutantmonkey/csp_referrer_fix

fix CSP referrer policy
This commit is contained in:
Andrei Marcu 2015-10-12 10:01:50 -04:00
commit ff1d9f56a1
8 changed files with 26 additions and 14 deletions

View File

@ -25,8 +25,8 @@ Command-line options
- ```-maxsize 4294967296``` maximum upload file size in bytes (default 4GB) - ```-maxsize 4294967296``` maximum upload file size in bytes (default 4GB)
- ```-certfile path/to/your.crt``` -- Path to the ssl certificate (required if you want to use the https server) - ```-certfile path/to/your.crt``` -- Path to the ssl certificate (required if you want to use the https server)
- ```-keyfile path/to/your.key``` -- Path to the ssl key (required if you want to use the https server) - ```-keyfile path/to/your.key``` -- Path to the ssl key (required if you want to use the https server)
- ```-contentsecuritypolicy "..."``` -- Content-Security-Policy header for pages (default is "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; referrer none;") - ```-contentsecuritypolicy "..."``` -- Content-Security-Policy header for pages (default is "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; referrer origin;")
- ```-filecontentsecuritypolicy "..."``` -- Content-Security-Policy header for files (default is "default-src 'none'; img-src 'self'; object-src 'self'; media-src 'self'; sandbox; referrer none;"") - ```-filecontentsecuritypolicy "..."``` -- Content-Security-Policy header for files (default is "default-src 'none'; img-src 'self'; object-src 'self'; media-src 'self'; sandbox; referrer origin;"")
- ```-xframeoptions "..." ``` -- X-Frame-Options header (default is "SAMEORIGIN") - ```-xframeoptions "..." ``` -- X-Frame-Options header (default is "SAMEORIGIN")
- ```-remoteuploads``` -- (optionally) enable remote uploads (/upload?url=https://...) - ```-remoteuploads``` -- (optionally) enable remote uploads (/upload?url=https://...)
- ```-realip``` -- (optionally) let linx-server know you (nginx, etc) are providing the X-Real-IP and/or X-Forwarded-For headers. - ```-realip``` -- (optionally) let linx-server know you (nginx, etc) are providing the X-Real-IP and/or X-Forwarded-For headers.

12
csrf.go
View File

@ -6,17 +6,19 @@ import (
) )
func strictReferrerCheck(r *http.Request, prefix string, whitelistHeaders []string) bool { func strictReferrerCheck(r *http.Request, prefix string, whitelistHeaders []string) bool {
p := strings.TrimSuffix(prefix, "/")
if origin := r.Header.Get("Origin"); origin != "" {
// if there's an Origin header, check it and ignore the rest
return strings.HasPrefix(origin, p)
}
for _, header := range whitelistHeaders { for _, header := range whitelistHeaders {
if r.Header.Get(header) != "" { if r.Header.Get(header) != "" {
return true return true
} }
} }
if referrer := r.Header.Get("Referer"); !strings.HasPrefix(referrer, prefix) { if referrer := r.Header.Get("Referer"); !strings.HasPrefix(referrer, p) {
return false
}
if origin := r.Header.Get("Origin"); origin != "" && !strings.HasPrefix(origin, strings.TrimSuffix(prefix, "/")) {
return false return false
} }

View File

@ -26,7 +26,8 @@ func fileServeHandler(c web.C, w http.ResponseWriter, r *http.Request) {
if !Config.allowHotlink { if !Config.allowHotlink {
referer := r.Header.Get("Referer") referer := r.Header.Get("Referer")
if referer != "" && !strings.HasPrefix(referer, Config.siteURL) { prefix := strings.TrimSuffix(Config.siteURL, "/")
if referer != "" && !strings.HasPrefix(referer, prefix) {
w.WriteHeader(403) w.WriteHeader(403)
return return
} }

View File

@ -86,7 +86,10 @@ func oopsHandler(c web.C, w http.ResponseWriter, r *http.Request, rt RespType, m
func badRequestHandler(c web.C, w http.ResponseWriter, r *http.Request) { func badRequestHandler(c web.C, w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) err := Templates["400.html"].ExecuteWriter(pongo2.Context{}, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
} }
func unauthorizedHandler(c web.C, w http.ResponseWriter, r *http.Request) { func unauthorizedHandler(c web.C, w http.ResponseWriter, r *http.Request) {

View File

@ -184,10 +184,10 @@ func main() {
flag.StringVar(&Config.remoteAuthFile, "remoteauthfile", "", flag.StringVar(&Config.remoteAuthFile, "remoteauthfile", "",
"path to a file containing newline-separated scrypted auth keys for remote uploads") "path to a file containing newline-separated scrypted auth keys for remote uploads")
flag.StringVar(&Config.contentSecurityPolicy, "contentsecuritypolicy", flag.StringVar(&Config.contentSecurityPolicy, "contentsecuritypolicy",
"default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; referrer none;", "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; referrer origin;",
"value of default Content-Security-Policy header") "value of default Content-Security-Policy header")
flag.StringVar(&Config.fileContentSecurityPolicy, "filecontentsecuritypolicy", flag.StringVar(&Config.fileContentSecurityPolicy, "filecontentsecuritypolicy",
"default-src 'none'; img-src 'self'; object-src 'self'; media-src 'self'; sandbox; referrer none;", "default-src 'none'; img-src 'self'; object-src 'self'; media-src 'self'; sandbox; referrer origin;",
"value of Content-Security-Policy header for file access") "value of Content-Security-Policy header for file access")
flag.StringVar(&Config.xFrameOptions, "xframeoptions", "SAMEORIGIN", flag.StringVar(&Config.xFrameOptions, "xframeoptions", "SAMEORIGIN",
"value of X-Frame-Options header") "value of X-Frame-Options header")

View File

@ -45,8 +45,9 @@ func populateTemplatesMap(tSet *pongo2.TemplateSet, tMap map[string]*pongo2.Temp
"index.html", "index.html",
"paste.html", "paste.html",
"API.html", "API.html",
"404.html", "400.html",
"401.html", "401.html",
"404.html",
"oops.html", "oops.html",
"display/audio.html", "display/audio.html",

5
templates/400.html Normal file
View File

@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block content %}
400 Bad Request
{% endblock %}

View File

@ -46,7 +46,7 @@ type Upload struct {
} }
func uploadPostHandler(c web.C, w http.ResponseWriter, r *http.Request) { func uploadPostHandler(c web.C, w http.ResponseWriter, r *http.Request) {
if !strictReferrerCheck(r, Config.siteURL, []string{"Linx-Delete-Key", "Linx-Expiry", "Linx-Randomize"}) { if !strictReferrerCheck(r, Config.siteURL, []string{"Linx-Delete-Key", "Linx-Expiry", "Linx-Randomize", "X-Requested-With"}) {
badRequestHandler(c, w, r) badRequestHandler(c, w, r)
return return
} }
@ -145,7 +145,7 @@ func uploadRemote(c web.C, w http.ResponseWriter, r *http.Request) {
} }
} else { } else {
// strict referrer checking is mandatory without remote auth keys // strict referrer checking is mandatory without remote auth keys
if !strictReferrerCheck(r, Config.siteURL, []string{"Linx-Delete-Key", "Linx-Expiry", "Linx-Randomize"}) { if !strictReferrerCheck(r, Config.siteURL, []string{"Linx-Delete-Key", "Linx-Expiry", "Linx-Randomize", "X-Requested-With"}) {
badRequestHandler(c, w, r) badRequestHandler(c, w, r)
return return
} }