client/web: add Sec-Fetch-Site CSRF protection (#16046)

RELNOTE=Fix CSRF errors in the client Web UI

Replace gorilla/csrf with a Sec-Fetch-Site based CSRF protection
middleware that falls back to comparing the Host & Origin headers if no
SFS value is passed by the client.

Add an -origin override to the web CLI that allows callers to specify
the origin at which the web UI will be available if it is hosted behind
a reverse proxy or within another application via CGI.

Updates #14872
Updates #15065

Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
This commit is contained in:
Patrick O'Doherty
2025-05-22 12:26:02 -07:00
committed by GitHub
parent 3ee4c60ff0
commit a05924a9e5
8 changed files with 184 additions and 169 deletions
+5
View File
@@ -43,6 +43,7 @@ Tailscale, as opposed to a CLI or a native app.
webf.BoolVar(&webArgs.cgi, "cgi", false, "run as CGI script")
webf.StringVar(&webArgs.prefix, "prefix", "", "URL prefix added to requests (for cgi or reverse proxies)")
webf.BoolVar(&webArgs.readonly, "readonly", false, "run web UI in read-only mode")
webf.StringVar(&webArgs.origin, "origin", "", "origin at which the web UI is served (if behind a reverse proxy or used with cgi)")
return webf
})(),
Exec: runWeb,
@@ -53,6 +54,7 @@ var webArgs struct {
cgi bool
prefix string
readonly bool
origin string
}
func tlsConfigFromEnvironment() *tls.Config {
@@ -115,6 +117,9 @@ func runWeb(ctx context.Context, args []string) error {
if webArgs.readonly {
opts.Mode = web.ReadOnlyServerMode
}
if webArgs.origin != "" {
opts.OriginOverride = webArgs.origin
}
webServer, err := web.NewServer(opts)
if err != nil {
log.Printf("tailscale.web: %v", err)