fix(security): stream tickets instead of session tokens in URLs (FLAW-22)
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m32s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m32s
WebSocket and EventSource put the 30-day session token into the URL, where proxies log it. The app now gets a one-time ticket right before connecting (POST /auth/stream-ticket, 60 s, bound to the token version); ?token= is no longer accepted for streams, non-browser clients may use the Authorization header. With BASE_URL set, CORS allows only that origin and WebSocket upgrades only it or the requested host; credentials are off (no cookies exist). Logout, ending all sessions, a new password and deactivation close all live streams of the account; clients with a valid session reconnect with a fresh ticket. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5c711c2cf7
commit
f57a9884d1
17 files changed
+335
-41
No files matched your search
@@ -891,7 +891,8 @@ func TestSSEGlobalEndpoint(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
req = httptest.NewRequest(http.MethodGet, "/api/v1/events?token="+token, nil).WithContext(ctx)
|
||||
req = httptest.NewRequest(http.MethodGet, "/api/v1/events", nil).WithContext(ctx)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rec = httptest.NewRecorder()
|
||||
|
||||
go func() {
|
||||
@@ -1147,7 +1148,8 @@ func TestTokenBlacklistingAndTokenVersionRevocation(t *testing.T) {
|
||||
}
|
||||
|
||||
// Also check authenticateUserFromReq rejects token1
|
||||
req = httptest.NewRequest(http.MethodGet, "/api/v1/ws?token="+token1, nil)
|
||||
req = httptest.NewRequest(http.MethodGet, "/api/v1/ws", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token1)
|
||||
if uid := srv.authenticateUserFromReq(req); uid != "" {
|
||||
t.Fatalf("authenticateUserFromReq should reject blacklisted token1, got uid %q", uid)
|
||||
}
|
||||
@@ -1468,7 +1470,8 @@ func TestAPIKeysOnlyDeliverData(t *testing.T) {
|
||||
t.Fatalf("key must not write into lists its owner cannot see, got %d", code)
|
||||
}
|
||||
// Keys never open live streams (those carry the user's data)
|
||||
streamReq := httptest.NewRequest(http.MethodGet, "/api/v1/events?token="+full.RawKey, nil)
|
||||
streamReq := httptest.NewRequest(http.MethodGet, "/api/v1/events", nil)
|
||||
streamReq.Header.Set("Authorization", "Bearer "+full.RawKey)
|
||||
if uid := srv.authenticateUserFromReq(streamReq); uid != "" {
|
||||
t.Fatalf("API key must not authenticate a live stream")
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user