Skip to content

Commit f6810fd

Browse files
authored
x.sessions: verify HMAC signatures when extracting sessions IDs from cookies (#26199)
1 parent ecc9460 commit f6810fd

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

vlib/x/sessions/sessions.v

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,15 +170,19 @@ pub fn (mut s Sessions[T]) resave[X](mut ctx X, data T) ! {
170170
}
171171

172172
// get_session_id retrieves the current session id, if it is set.
173+
// The HMAC signature is verified when extracting from cookies.
173174
pub fn (s &Sessions[T]) get_session_id[X](ctx X) ?string {
174175
// first check session id from `ctx`
175176
sid_from_ctx := ctx.CurrentSession.session_id
176177
if sid_from_ctx != '' {
177178
return sid_from_ctx
178179
} else if cookie := ctx.get_cookie(s.cookie_options.cookie_name) {
179-
// check request headers for the session_id cookie
180-
a := cookie.split('.')
181-
return a[0]
180+
// check request headers for the session_id cookie and verify HMAC signature
181+
sid, valid := verify_session_id(cookie, s.secret)
182+
if valid {
183+
return sid
184+
}
185+
return none
182186
} else {
183187
// check the Set-Cookie headers on the response for a session id
184188
for cookie in ctx.res.cookies() {

vlib/x/sessions/tests/session_test.v

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,44 @@ fn test_session_id() {
1919
verified_sid, valid := sessions.verify_session_id(sid_with_hmac, secret)
2020

2121
assert unverified_sid == verified_sid
22-
assert valid == true
22+
assert valid
23+
}
24+
25+
fn test_forged_signature_rejected() {
26+
// Create a valid session ID
27+
sid, _ := sessions.new_session_id(secret)
28+
29+
// Forge a cookie with valid session ID but invalid signature
30+
forged_cookie := '${sid}.INVALID_SIGNATURE'
31+
verified_sid, valid := sessions.verify_session_id(forged_cookie, secret)
32+
33+
// Forged signature must be rejected
34+
assert !valid
35+
assert verified_sid == sid
36+
}
37+
38+
fn test_wrong_secret_rejected() {
39+
// Create a session with one secret
40+
_, signed_cookie := sessions.new_session_id(secret)
41+
42+
// Try to verify with a different secret
43+
wrong_secret := 'wrong_secret'.bytes()
44+
_, valid := sessions.verify_session_id(signed_cookie, wrong_secret)
45+
46+
// Must be rejected when using wrong secret
47+
assert !valid
48+
}
49+
50+
fn test_malformed_cookie_rejected() {
51+
// Cookie without signature separator
52+
_, valid1 := sessions.verify_session_id('just_a_session_id', secret)
53+
assert !valid1
54+
55+
// Empty cookie
56+
_, valid2 := sessions.verify_session_id('', secret)
57+
assert !valid2
58+
59+
// Cookie with empty parts
60+
_, valid3 := sessions.verify_session_id('.', secret)
61+
assert !valid3
2362
}

0 commit comments

Comments
 (0)