Skip to content

Commit 3d5703b

Browse files
srenatusbradfitz
authored andcommitted
net/http: add support for SameSite option in http.Cookie
The same-site cookie attribute prevents a cookie from being sent along with cross-site requests. The main goal is mitigate the risk of cross-origin information leakage and provides some protection against cross-site request forgery attacks. This change adds the option to http.Cookie so it can be stored and passed to HTTP clients. Spec: https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 Fixes #15867 Based on reedloden@eb31a0f by Reed Loden <[email protected]> Change-Id: I98c8a9a92358b2f632990576879759e3aff38cff Reviewed-on: https://go-review.googlesource.com/79919 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 4da84ad commit 3d5703b

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

src/net/http/cookie.go

+34
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,25 @@ type Cookie struct {
3131
MaxAge int
3232
Secure bool
3333
HttpOnly bool
34+
SameSite SameSite
3435
Raw string
3536
Unparsed []string // Raw text of unparsed attribute-value pairs
3637
}
3738

39+
// SameSite allows a server define a cookie attribute making it impossible to
40+
// the browser send this cookie along with cross-site requests. The main goal
41+
// is mitigate the risk of cross-origin information leakage, and provides some
42+
// protection against cross-site request forgery attacks.
43+
//
44+
// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details.
45+
type SameSite int
46+
47+
const (
48+
SameSiteDefaultMode SameSite = iota + 1
49+
SameSiteLaxMode
50+
SameSiteStrictMode
51+
)
52+
3853
// readSetCookies parses all "Set-Cookie" values from
3954
// the header h and returns the successfully parsed Cookies.
4055
func readSetCookies(h Header) []*Cookie {
@@ -83,6 +98,17 @@ func readSetCookies(h Header) []*Cookie {
8398
continue
8499
}
85100
switch lowerAttr {
101+
case "samesite":
102+
lowerVal := strings.ToLower(val)
103+
switch lowerVal {
104+
case "lax":
105+
c.SameSite = SameSiteLaxMode
106+
case "strict":
107+
c.SameSite = SameSiteStrictMode
108+
default:
109+
c.SameSite = SameSiteDefaultMode
110+
}
111+
continue
86112
case "secure":
87113
c.Secure = true
88114
continue
@@ -184,6 +210,14 @@ func (c *Cookie) String() string {
184210
if c.Secure {
185211
b.WriteString("; Secure")
186212
}
213+
switch c.SameSite {
214+
case SameSiteDefaultMode:
215+
b.WriteString("; SameSite")
216+
case SameSiteLaxMode:
217+
b.WriteString("; SameSite=Lax")
218+
case SameSiteStrictMode:
219+
b.WriteString("; SameSite=Strict")
220+
}
187221
return b.String()
188222
}
189223

src/net/http/cookie_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ var writeSetCookiesTests = []struct {
6565
&Cookie{Name: "cookie-11", Value: "invalid-expiry", Expires: time.Date(1600, 1, 1, 1, 1, 1, 1, time.UTC)},
6666
"cookie-11=invalid-expiry",
6767
},
68+
{
69+
&Cookie{Name: "cookie-12", Value: "samesite-default", SameSite: SameSiteDefaultMode},
70+
"cookie-12=samesite-default; SameSite",
71+
},
72+
{
73+
&Cookie{Name: "cookie-13", Value: "samesite-lax", SameSite: SameSiteLaxMode},
74+
"cookie-13=samesite-lax; SameSite=Lax",
75+
},
76+
{
77+
&Cookie{Name: "cookie-14", Value: "samesite-strict", SameSite: SameSiteStrictMode},
78+
"cookie-14=samesite-strict; SameSite=Strict",
79+
},
6880
// The "special" cookies have values containing commas or spaces which
6981
// are disallowed by RFC 6265 but are common in the wild.
7082
{
@@ -241,6 +253,33 @@ var readSetCookiesTests = []struct {
241253
Raw: "ASP.NET_SessionId=foo; path=/; HttpOnly",
242254
}},
243255
},
256+
{
257+
Header{"Set-Cookie": {"samesitedefault=foo; SameSite"}},
258+
[]*Cookie{{
259+
Name: "samesitedefault",
260+
Value: "foo",
261+
SameSite: SameSiteDefaultMode,
262+
Raw: "samesitedefault=foo; SameSite",
263+
}},
264+
},
265+
{
266+
Header{"Set-Cookie": {"samesitelax=foo; SameSite=Lax"}},
267+
[]*Cookie{{
268+
Name: "samesitelax",
269+
Value: "foo",
270+
SameSite: SameSiteLaxMode,
271+
Raw: "samesitelax=foo; SameSite=Lax",
272+
}},
273+
},
274+
{
275+
Header{"Set-Cookie": {"samesitestrict=foo; SameSite=Strict"}},
276+
[]*Cookie{{
277+
Name: "samesitestrict",
278+
Value: "foo",
279+
SameSite: SameSiteStrictMode,
280+
Raw: "samesitestrict=foo; SameSite=Strict",
281+
}},
282+
},
244283
// Make sure we can properly read back the Set-Cookie headers we create
245284
// for values containing spaces or commas:
246285
{

src/net/http/cookiejar/jar.go

+10
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ type entry struct {
9393
Value string
9494
Domain string
9595
Path string
96+
SameSite string
9697
Secure bool
9798
HttpOnly bool
9899
Persistent bool
@@ -418,6 +419,15 @@ func (j *Jar) newEntry(c *http.Cookie, now time.Time, defPath, host string) (e e
418419
e.Secure = c.Secure
419420
e.HttpOnly = c.HttpOnly
420421

422+
switch c.SameSite {
423+
case http.SameSiteDefaultMode:
424+
e.SameSite = "SameSite"
425+
case http.SameSiteStrictMode:
426+
e.SameSite = "SameSite=Strict"
427+
case http.SameSiteLaxMode:
428+
e.SameSite = "SameSite=Lax"
429+
}
430+
421431
return e, false, nil
422432
}
423433

0 commit comments

Comments
 (0)