mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-11-04 16:40:21 +00:00
fix(nat): scrub dashboard-issued credentials from all accepted token channels
The initial selective strip covered only the Authorization header, but the dashboard also accepts its JWT via the ?token= query parameter and the nz-jwt cookie (jwt.go TokenLookup channels). A dashboard credential arriving through those channels would still reach a NAT backend. Apply the same classify-then-strip rule to all three channels at NAT ingress: values verified as dashboard-issued are removed, foreign values are preserved byte-for-byte. Adds a ServeNAT flow test exercising the live classifier and a wiring test pinning the gate injection in main().
This commit is contained in:
1 parent
40240ed02b
commit
3ad985f36e
12 files changed
+806
-82
No files matched your search
@@ -4,6 +4,7 @@ package rpc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/nezhahq/nezha/model"
|
||||
@@ -39,13 +40,17 @@ func TestPrepareNATCapabilityDefaultStripsDashboardCredentials(t *testing.T) {
|
||||
// Given
|
||||
installNATCredentialTestGate(t)
|
||||
for name, credential := range map[string]string{
|
||||
"dashboard jwt": natTestDashboardJWT,
|
||||
"expired dashboard jwt": natTestDashboardExpiredJWT,
|
||||
"dashboard api token": natTestDashboardAPIToken,
|
||||
"dashboard jwt": natTestDashboardJWTValue,
|
||||
"expired dashboard jwt": natTestDashboardExpiredJWTValue,
|
||||
"dashboard api token": natTestDashboardPATValue,
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
request := &http.Request{Header: make(http.Header)}
|
||||
request.Header.Set("Authorization", credential)
|
||||
request := &http.Request{
|
||||
Header: make(http.Header),
|
||||
URL: &url.URL{Path: "/nat", RawQuery: "keep=1&token=" + credential},
|
||||
}
|
||||
request.Header.Set("Authorization", "Bearer "+credential)
|
||||
request.Header.Set("Cookie", "sid=abc; nz-jwt="+credential)
|
||||
|
||||
// When
|
||||
lease, err := prepareNATCapability(request, &model.NAT{Common: model.Common{ID: 91}, ServerID: 81})
|
||||
@@ -58,7 +63,13 @@ func TestPrepareNATCapabilityDefaultStripsDashboardCredentials(t *testing.T) {
|
||||
t.Fatal("default NAT capability hook unexpectedly activated")
|
||||
}
|
||||
if got := request.Header.Get("Authorization"); got != "" {
|
||||
t.Fatalf("default NAT capability hook retained dashboard credential %q", got)
|
||||
t.Fatalf("default NAT capability hook retained dashboard credential in Authorization %q", got)
|
||||
}
|
||||
if got := request.URL.RawQuery; got != "keep=1" {
|
||||
t.Fatalf("default NAT capability hook retained dashboard credential in query %q", got)
|
||||
}
|
||||
if got := request.Header.Get("Cookie"); got != "sid=abc" {
|
||||
t.Fatalf("default NAT capability hook retained dashboard credential in cookie %q", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -101,3 +112,38 @@ func TestPrepareNATCapabilityDefaultKeepsForeignAndMissingAuthorization(t *testi
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareNATCapabilityDefaultKeepsForeignAndMissingQueryAndCookie(t *testing.T) {
|
||||
// Given
|
||||
installNATCredentialTestGate(t)
|
||||
for name, tc := range map[string]struct{ rawQuery, cookie string }{
|
||||
"foreign values": {"keep=1&token=" + natTestForeignJWTValue + "&a=%2Fx", "sid=abc; nz-jwt=" + natTestForeignJWTValue},
|
||||
"empty values": {"keep=1&token=", "nz-jwt="},
|
||||
"missing channel": {"keep=1", "sid=abc"},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
request := &http.Request{
|
||||
Header: make(http.Header),
|
||||
URL: &url.URL{Path: "/nat", RawQuery: tc.rawQuery},
|
||||
}
|
||||
request.Header.Set("Cookie", tc.cookie)
|
||||
|
||||
// When
|
||||
lease, err := prepareNATCapability(request, &model.NAT{Common: model.Common{ID: 91}, ServerID: 81})
|
||||
|
||||
// Then
|
||||
if err != nil {
|
||||
t.Fatalf("default NAT capability hook returned error: %v", err)
|
||||
}
|
||||
if lease.active {
|
||||
t.Fatal("default NAT capability hook unexpectedly activated")
|
||||
}
|
||||
if got := request.URL.RawQuery; got != tc.rawQuery {
|
||||
t.Fatalf("default NAT capability hook changed query to %q, want %q", got, tc.rawQuery)
|
||||
}
|
||||
if got := request.Header.Get("Cookie"); got != tc.cookie {
|
||||
t.Fatalf("default NAT capability hook changed cookie to %q, want %q", got, tc.cookie)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user