如何设置多值HTTP标头,例如Content-Security-Policy?

时间:2014-07-30 03:46:57

标签: go http-headers content-security-policy

我试图在http.ResponseWriter对象上设置Content-Security-Policy标头。这是一个包含多个值的标头。我的问题是http.Header的所有方法都采用单个键和单个值。例如,Set() method看起来像这样:

func (h Header) Set(key, value string)

没有方法可以为标头字段分配值的 slice 。我想要一个看起来像这样的标题。

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"},
}

这将创建标题,但我不知道如何将其与http.ResponseWriter对象相关联。此外,如果我以某种方式能够用上面的标题替换ResponseWriter的标题,我是否必须手动设置Content-Length字段?

3 个答案:

答案 0 :(得分:2)

我不确定我是否完全理解这个问题,但是Content-Security-Policy期望一个标题包含一个以;分隔的列表。

如果你想使用切片,你总是可以使用这样的东西:

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, "; "))

此外,如果您想使用不同的值多次发送标题(我认为您最初的意图),您可以使用header.Add

  

添加将键值对添加到标题中。 附加到与密钥相关联的任何现有值。

如果要在http处理程序中使用它,请使用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
}

答案 1 :(得分:1)

这不直接(尚未)解决CSP问题,但确实涵盖了“其他4个”安全标头

http://godoc.org/github.com/kr/secureheader

答案 2 :(得分:0)

我创建了一个中间件来设置CSP标头。

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)
    })
}