Skip to content

Commit af13620

Browse files
authored
feat(cookie): prevent aggressive session cookie expiration (#284)
* fix(cookie): prevent aggressive session cookie expiration * chore: update docs
1 parent a009983 commit af13620

2 files changed

Lines changed: 41 additions & 0 deletions

File tree

core/api/session.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,44 @@ func GetSessionStore(r *http.Request, key string) (*sessions.Session, error) {
6060
return getStore().Get(r, key)
6161
}
6262

63+
const sessionCookiePrefix = "INFINI-SESSION-"
64+
65+
// cookieSizeCleanupThreshold is the Cookie header size (bytes) beyond which
66+
// foreign session cookies are expired. Below this threshold multiple services
67+
// on the same host can coexist without interfering with each other's sessions.
68+
const cookieSizeCleanupThreshold = 6 * 1024
69+
70+
// cleanupForeignSessionCookies expires INFINI-SESSION-* cookies that belong to
71+
// other services running on the same host (but different ports).
72+
// Per RFC 6265 cookies are scoped by domain only, not by port, so multiple
73+
// services on localhost accumulate each other's session cookies and can exceed
74+
// the 8192-byte header limit.
75+
//
76+
// To avoid logging out other services unnecessarily, cleanup only triggers when
77+
// the total Cookie header approaches the dangerous size limit.
78+
func cleanupForeignSessionCookies(w http.ResponseWriter, r *http.Request) {
79+
cookieHeader := r.Header.Get("Cookie")
80+
if len(cookieHeader) < cookieSizeCleanupThreshold {
81+
return
82+
}
83+
84+
myName := getSessionName()
85+
for _, c := range r.Cookies() {
86+
if strings.HasPrefix(c.Name, sessionCookiePrefix) && c.Name != myName {
87+
http.SetCookie(w, &http.Cookie{
88+
Name: c.Name,
89+
Value: "",
90+
Path: "/",
91+
MaxAge: -1,
92+
HttpOnly: true,
93+
})
94+
}
95+
}
96+
}
97+
6398
func GetSession(w http.ResponseWriter, r *http.Request, key string) (bool, interface{}) {
99+
cleanupForeignSessionCookies(w, r)
100+
64101
s := getStore()
65102
session, err := s.Get(r, getSessionName())
66103

@@ -107,6 +144,8 @@ func SetSession(w http.ResponseWriter, r *http.Request, key string, value interf
107144
}
108145

109146
func ForceSetSession(w http.ResponseWriter, r *http.Request, key string, value interface{}, force bool) bool {
147+
cleanupForeignSessionCookies(w, r)
148+
110149
s := getStore()
111150
var (
112151
session *sessions.Session
@@ -204,6 +243,7 @@ func DelSession(w http.ResponseWriter, r *http.Request, key string) bool {
204243

205244
// DestroySession remove session by creating a new empty session
206245
func DestroySession(w http.ResponseWriter, r *http.Request) bool {
246+
cleanupForeignSessionCookies(w, r)
207247

208248
s := getStore()
209249
session, err := s.New(r, getSessionName())

docs/content.en/docs/release-notes/_index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Information about release notes of INFINI Framework is provided here.
1919
- feat(keystore): support large stdin secrets (>1024 bytes) and multiline #271
2020
- feat(cors): add X-SERVICE-ID to allowed CORS headers #275
2121
- feat: output HTTP access logs to file
22+
- feat(cookie): prevent aggressive session cookie expiration #284
2223

2324
### 🐛 Bug fix
2425
### ✈️ Improvements

0 commit comments

Comments
 (0)