mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 11:15:03 +03:00
fix(web): match the WebSocket origin on scheme and port, not only host
The live-update socket accepted any Origin whose host name matched, but cookies do not separate ports or schemes, so a page served by another service on the same host name could open it with the admin's session. Only http(s) origins are accepted now (https when the panel terminates TLS itself), and the port must match whenever the Host header has one.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Cookies do not separate ports or schemes, so another service on the panel's host name
|
||||
// must not be able to open the admin's live-update socket from the admin's browser.
|
||||
func TestCheckSameOriginComparesSchemeAndPort(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name, host, origin string
|
||||
tls bool
|
||||
want bool
|
||||
}{
|
||||
{"no origin header", "panel.example.com:2053", "", false, true},
|
||||
{"same host and port", "panel.example.com:2053", "http://panel.example.com:2053", false, true},
|
||||
{"default port omitted by the browser", "panel.example.com:443", "https://panel.example.com", true, true},
|
||||
{"behind a proxy without a port", "panel.example.com", "https://panel.example.com", false, true},
|
||||
{"bare IPv6 host", "[::1]", "http://[::1]", false, true},
|
||||
{"another port on the same host", "panel.example.com:2053", "http://panel.example.com:8080", false, false},
|
||||
{"plain http origin on a TLS panel", "panel.example.com:2053", "http://panel.example.com:2053", true, false},
|
||||
{"non-web scheme", "panel.example.com:2053", "chrome-extension://panel.example.com:2053", false, false},
|
||||
{"another host", "panel.example.com:2053", "http://evil.example.com:2053", false, false},
|
||||
} {
|
||||
req := httptest.NewRequest(http.MethodGet, "/ws", nil)
|
||||
req.Host = tc.host
|
||||
if tc.origin != "" {
|
||||
req.Header.Set("Origin", tc.origin)
|
||||
}
|
||||
if tc.tls {
|
||||
req.TLS = &tls.ConnectionState{}
|
||||
} else {
|
||||
req.TLS = nil
|
||||
}
|
||||
if got := checkSameOrigin(req); got != tc.want {
|
||||
t.Errorf("%s: checkSameOrigin(Host %q, Origin %q) = %v, want %v", tc.name, tc.host, tc.origin, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user