3746a30126
* fix: enforce origin validation on websocket upgrades The gateway /ws upgrader hardcoded CheckOrigin to true, so any web page could open a socket to the local backend and drive session/shell actions (cross-site WebSocket hijacking → RCE on the host). Both upgraders now share checkWebSocketOrigin: no Origin header is allowed (non-browser clients), same-hostname and loopback↔loopback origins are allowed, everything else is rejected. Replaces the terminal handler's prefix-based check, which accepted origins like http://localhost.attacker.tld. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor: share origin trust policy between cors and websocket checks Review feedback on #1698: the CORS middleware and the WebSocket upgrader carried two copies of the same origin policy, which could silently diverge. Both now delegate to httpmw.AllowedOrigin, which also rejects URL components that never appear in a browser Origin header (userinfo, path, query, fragment, opaque data). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Kandev Agent <agent@kandev.dev> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
24 lines
756 B
Go
24 lines
756 B
Go
package websocket
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/kandev/kandev/internal/common/httpmw"
|
|
)
|
|
|
|
// checkWebSocketOrigin validates the Origin header on WebSocket upgrade
|
|
// requests to prevent cross-site WebSocket hijacking: without it, any web
|
|
// page the user visits could open a socket to the local backend and drive
|
|
// session/shell actions on the host.
|
|
//
|
|
// Requests without an Origin header are allowed (non-browser clients such as
|
|
// the CLI or curl); everything else defers to the shared origin trust policy
|
|
// in httpmw.AllowedOrigin, the same policy the CORS middleware enforces.
|
|
func checkWebSocketOrigin(r *http.Request) bool {
|
|
origin := r.Header.Get("Origin")
|
|
if origin == "" {
|
|
return true
|
|
}
|
|
return httpmw.AllowedOrigin(origin, r.Host)
|
|
}
|