I'm trying to set the Content-Security-Policy header on a http.ResponseWriter object. This is a header with multiple values. My problem is that all the methods for http.Header take a single key and a single value. For example, the Set() method looks like this:
func (h Header) Set(key, value string)
There's no method for assigning a slice of values to a header field. I want a header that looks like this.
header := http.Header{
"Content-Type": {"text/html; charset=UTF-8"},
"Content-Security-Policy": {"default-src 'self'", "font-src themes.googleusercontent.com", "frame-src 'none'", "style-src 'self' fonts.googleapis.com"},
}
This will create the header, but I don't know how to associate it with the http.ResponseWriter object. Furthermore, if I were somehow able to replace the ResponseWriter's header with the header above, would I have to set the Content-Length field by hand?
I'm not sure I fully understand the problem, however Content-Security-Policy
expects one header that contains a list separated by ;
.
If you want to use a slice you can always use something like this:
csp := []string{"default-src: 'self'", "font-src: 'fonts.googleapis.com'", "frame-src: 'none'"}
header := http.Header{
"Content-Type": {"text/html; charset=UTF-8"},
}
header.Set("Content-Security-Policy", strings.Join(csp, "; "))
Also if you want to send the header multiple times with different values (like you originally intended, I think), you can use header.Add
.
Add adds the key, value pair to the header. It appends to any existing values associated with key.
If you want to use that in your http handler, get the header with ResponseWriter.Header():
func Handler(rw http.ResponseWriter, req *http.Request) {
header := rw.Header()
csp := []string{"default-src: 'self'", "font-src: 'fonts.googleapis.com'", "frame-src: 'none'"}
header.Set("Content-Type": "text/html; charset=UTF-8")
header.Set("Content-Security-Policy", strings.Join(csp, "; "))
rw.WriteHeader(200) //or write anything really
}
This doesn't address CSP directly (yet), but it does cover "the other 4" security headers
I created a middleware to set the CSP header.
package main
import (
"gorila-mux/ctrls"
"log"
"net/http"
"github.com/gorilla/context"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/", ctrls.HomeHandler)
r.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir("public/"))))
http.Handle("/", r)
r.Use(setCSPHeaders)
log.Print("Project is serving on port 7000 : http://localhost:7000")
http.ListenAndServe(":7000", context.ClearHandler(http.DefaultServeMux))
}
func setCSPHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self'; object-src 'self';style-src 'self' img-src 'self'; media-src 'self'; frame-ancestors 'self'; frame-src 'self'; connect-src 'self'")
next.ServeHTTP(w, r)
})
}