mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-26 11:11:01 +00:00
cmd/derper,tsweb: consistently add HTTP security headers (#8579)
Add a few helper functions in tsweb to add common security headers to handlers. Use those functions for all non-tailscaled-facing endpoints in derper. Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
parent
8cda647a0f
commit
96d7af3469
@ -182,8 +182,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
mux.HandleFunc("/derp/probe", probeHandler)
|
mux.HandleFunc("/derp/probe", probeHandler)
|
||||||
go refreshBootstrapDNSLoop()
|
go refreshBootstrapDNSLoop()
|
||||||
mux.HandleFunc("/bootstrap-dns", handleBootstrapDNS)
|
mux.HandleFunc("/bootstrap-dns", tsweb.BrowserHeaderHandlerFunc(handleBootstrapDNS))
|
||||||
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tsweb.AddBrowserHeaders(w)
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
io.WriteString(w, `<html><body>
|
io.WriteString(w, `<html><body>
|
||||||
@ -203,6 +204,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
mux.Handle("/robots.txt", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
mux.Handle("/robots.txt", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
tsweb.AddBrowserHeaders(w)
|
||||||
io.WriteString(w, "User-agent: *\nDisallow: /\n")
|
io.WriteString(w, "User-agent: *\nDisallow: /\n")
|
||||||
}))
|
}))
|
||||||
mux.Handle("/generate_204", http.HandlerFunc(serveNoContent))
|
mux.Handle("/generate_204", http.HandlerFunc(serveNoContent))
|
||||||
@ -277,18 +279,6 @@ func main() {
|
|||||||
defer tlsActiveVersion.Add(label, -1)
|
defer tlsActiveVersion.Add(label, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set HTTP headers to appease automated security scanners.
|
|
||||||
//
|
|
||||||
// Security automation gets cranky when HTTPS sites don't
|
|
||||||
// set HSTS, and when they don't specify a content
|
|
||||||
// security policy for XSS mitigation.
|
|
||||||
//
|
|
||||||
// DERP's HTTP interface is only ever used for debug
|
|
||||||
// access (for which trivial safe policies work just
|
|
||||||
// fine), and by DERP clients which don't obey any of
|
|
||||||
// these browser-centric headers anyway.
|
|
||||||
w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
|
|
||||||
w.Header().Set("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'; form-action 'none'; base-uri 'self'; block-all-mixed-content; plugin-types 'none'")
|
|
||||||
mux.ServeHTTP(w, r)
|
mux.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
if *httpPort > -1 {
|
if *httpPort > -1 {
|
||||||
|
@ -51,7 +51,7 @@ func Debugger(mux *http.ServeMux) *DebugHandler {
|
|||||||
// Register this one directly on mux, rather than using
|
// Register this one directly on mux, rather than using
|
||||||
// ret.URL/etc, as we don't need another line of output on the
|
// ret.URL/etc, as we don't need another line of output on the
|
||||||
// index page. The /pprof/ index already covers it.
|
// index page. The /pprof/ index already covers it.
|
||||||
mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
|
mux.Handle("/debug/pprof/profile", BrowserHeaderHandler(http.HandlerFunc(pprof.Profile)))
|
||||||
|
|
||||||
ret.KVFunc("Uptime", func() any { return varz.Uptime() })
|
ret.KVFunc("Uptime", func() any { return varz.Uptime() })
|
||||||
ret.KV("Version", version.Long())
|
ret.KV("Version", version.Long())
|
||||||
@ -80,6 +80,7 @@ func (d *DebugHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddBrowserHeaders(w)
|
||||||
f := func(format string, args ...any) { fmt.Fprintf(w, format, args...) }
|
f := func(format string, args ...any) { fmt.Fprintf(w, format, args...) }
|
||||||
f("<html><body><h1>%s debug</h1><ul>", version.CmdName())
|
f("<html><body><h1>%s debug</h1><ul>", version.CmdName())
|
||||||
for _, kv := range d.kvs {
|
for _, kv := range d.kvs {
|
||||||
@ -97,7 +98,7 @@ func (d *DebugHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// entry in /debug/ for it.
|
// entry in /debug/ for it.
|
||||||
func (d *DebugHandler) Handle(slug, desc string, handler http.Handler) {
|
func (d *DebugHandler) Handle(slug, desc string, handler http.Handler) {
|
||||||
href := "/debug/" + slug
|
href := "/debug/" + slug
|
||||||
d.mux.Handle(href, Protected(handler))
|
d.mux.Handle(href, Protected(BrowserHeaderHandler(handler)))
|
||||||
d.URL(href, desc)
|
d.URL(href, desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,3 +423,37 @@ func Error(code int, msg string, err error) HTTPError {
|
|||||||
func VarzHandler(w http.ResponseWriter, r *http.Request) {
|
func VarzHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
varz.Handler(w, r)
|
varz.Handler(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddBrowserHeaders sets various HTTP security headers for browser-facing endpoints.
|
||||||
|
//
|
||||||
|
// The specific headers:
|
||||||
|
// - require HTTPS access (HSTS)
|
||||||
|
// - disallow iframe embedding
|
||||||
|
// - mitigate MIME confusion attacks
|
||||||
|
//
|
||||||
|
// These headers are based on
|
||||||
|
// https://infosec.mozilla.org/guidelines/web_security
|
||||||
|
func AddBrowserHeaders(w http.ResponseWriter) {
|
||||||
|
w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
|
||||||
|
w.Header().Set("Content-Security-Policy", "default-src 'self'; frame-ancestors 'none'; form-action 'none'; base-uri 'self'; block-all-mixed-content; plugin-types 'none'")
|
||||||
|
w.Header().Set("X-Frame-Options", "DENY")
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
}
|
||||||
|
|
||||||
|
// BrowserHeaderHandler wraps the provided http.Handler with a call to
|
||||||
|
// AddBrowserHeaders.
|
||||||
|
func BrowserHeaderHandler(h http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
AddBrowserHeaders(w)
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// BrowserHeaderHandlerFunc wraps the provided http.HandlerFunc with a call to
|
||||||
|
// AddBrowserHeaders.
|
||||||
|
func BrowserHeaderHandlerFunc(h http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
AddBrowserHeaders(w)
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user