From 0edfe02c5fc30c044d97542164174a3a976e1c68 Mon Sep 17 00:00:00 2001 From: Alan Greene Date: Wed, 30 Mar 2022 23:30:24 +0100 Subject: [PATCH] Validate Origin header on websocket connection upgrade Prevent cross-origin websocket hijacking by validating the Origin header on websocket connection upgrade requests matches the target Host header. This means that a websocket connection can only be established from pages served from the same origin. (cherry picked from commit b22ba6035f1f316ea2fd381fb0b7d435ea377787) --- pkg/router/router.go | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/pkg/router/router.go b/pkg/router/router.go index 465b06651..809408e1e 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -1,5 +1,5 @@ /* -Copyright 2019-2021 The Tekton Authors +Copyright 2019-2022 The Tekton Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -172,7 +172,7 @@ func NewProxyHandler(apiProxyPrefix string, cfg *rest.Config, keepalive time.Dur proxy.UseRequestLocation = true proxy.UseLocationHost = true - proxyServer := http.Handler(proxy) + proxyServer := protectWebSocket(proxy) return proxyServer, nil } @@ -191,3 +191,38 @@ func (s *Server) ServeOnListener(l net.Listener) error { } return server.Serve(l) } + +// isUpgradeRequest returns true if the given request is a connection upgrade request +func isUpgradeRequest(req *http.Request) bool { + connection := req.Header.Get("Connection") + return strings.ToLower(connection) == "upgrade" +} + +func checkUpgradeSameOrigin(req *http.Request) bool { + host := req.Host + origin := req.Header.Get("Origin") + + if len(origin) == 0 || !isUpgradeRequest(req) { + return true + } + + u, err := url.Parse(origin) + if err != nil { + return false + } + + return u.Host == host +} + +// Verify Origin header on Upgrade requests to prevent cross-origin websocket hijacking +func protectWebSocket(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + if !checkUpgradeSameOrigin(req) { + logging.Log.Warnf("websocket: Connection upgrade blocked, Host: %s, Origin: %s", req.Host, req.Header.Get("Origin")) + http.Error(w, "websocket: request origin not allowed", http.StatusForbidden) + return + } + + h.ServeHTTP(w, req) + }) +}