Skip to content

Commit 292c470

Browse files
Set cookies to have the Secure flag default to true (#739)
* Set Cookies to use the Secure Flag and default SameSite to None * Add secure flag test * Updated changelog and documentation for secure flag option
1 parent 12453fd commit 292c470

File tree

6 files changed

+32
-12
lines changed

6 files changed

+32
-12
lines changed

cmd/anubis/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ var (
5151
cookiePrefix = flag.String("cookie-prefix", "techaro.lol-anubis", "prefix for browser cookies created by Anubis")
5252
cookiePartitioned = flag.Bool("cookie-partitioned", false, "if true, sets the partitioned flag on Anubis cookies, enabling CHIPS support")
5353
hs512Secret = flag.String("hs512-secret", "", "secret used to sign JWTs, uses ed25519 if not set")
54+
cookieSecure = flag.Bool("cookie-secure", true, "if true, sets the secure flag on Anubis cookies")
5455
ed25519PrivateKeyHex = flag.String("ed25519-private-key-hex", "", "private key used to sign JWTs, if not set a random one will be assigned")
5556
ed25519PrivateKeyHexFile = flag.String("ed25519-private-key-hex-file", "", "file name containing value for ed25519-private-key-hex")
5657
metricsBind = flag.String("metrics-bind", ":9090", "network address to bind metrics to")
@@ -403,6 +404,7 @@ func main() {
403404
Target: *target,
404405
WebmasterEmail: *webmasterEmail,
405406
OpenGraph: policy.OpenGraph,
407+
CookieSecure: *cookieSecure,
406408
})
407409
if err != nil {
408410
log.Fatalf("can't construct libanubis.Server: %v", err)

docs/docs/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
1010
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1111

1212
## [Unreleased]
13+
<!-- This changes the project to: -->
14+
- Add `COOKIE_SECURE` option to set the cookie [Secure flag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies#block_access_to_your_cookies)
15+
- Sets cookie defaults to use [SameSite: None](https://web.dev/articles/samesite-cookies-explained)
1316

1417
- Determine the `BIND_NETWORK`/`--bind-network` value from the bind address ([#677](https://github.com/TecharoHQ/anubis/issues/677)).
1518
- Implement localization system. Find locale files in lib/localization/locales/.

docs/docs/admin/installation.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Anubis uses these environment variables for configuration:
6767
| `COOKIE_DYNAMIC_DOMAIN` | false | If set to true, automatically set cookie domain fields based on the hostname of the request. EG: if you are making a request to `anubis.techaro.lol`, the Anubis cookie will be valid for any subdomain of `techaro.lol`. |
6868
| `COOKIE_EXPIRATION_TIME` | `168h` | The amount of time the authorization cookie is valid for. |
6969
| `COOKIE_PARTITIONED` | `false` | If set to `true`, enables the [partitioned (CHIPS) flag](https://developers.google.com/privacy-sandbox/cookies/chips), meaning that Anubis inside an iframe has a different set of cookies than the domain hosting the iframe. |
70+
| `COOKIE_SECURE` | `true` | If set to `true`, enables the [Secure flag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies#block_access_to_your_cookies), meaning that the cookies will only be transmitted over HTTPS. If Anubis is used in an unsecure context (plain HTTP), this will be need to be set to false |
7071
| `DIFFICULTY` | `4` | The difficulty of the challenge, or the number of leading zeroes that must be in successful responses. |
7172
| `ED25519_PRIVATE_KEY_HEX` | unset | The hex-encoded ed25519 private key used to sign Anubis responses. If this is not set, Anubis will generate one for you. This should be exactly 64 characters long. See below for details. |
7273
| `ED25519_PRIVATE_KEY_HEX_FILE` | unset | Path to a file containing the hex-encoded ed25519 private key. Only one of this or its sister option may be set. |

lib/anubis_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ func TestCookieSettings(t *testing.T) {
262262

263263
CookieDomain: "127.0.0.1",
264264
CookiePartitioned: true,
265+
CookieSecure: true,
265266
CookieExpiration: anubis.CookieDefaultExpirationTime,
266267
})
267268

@@ -309,6 +310,10 @@ func TestCookieSettings(t *testing.T) {
309310
if ckie.Partitioned != srv.opts.CookiePartitioned {
310311
t.Errorf("wanted partitioned flag %v, got: %v", srv.opts.CookiePartitioned, ckie.Partitioned)
311312
}
313+
314+
if ckie.Secure != srv.opts.CookieSecure {
315+
t.Errorf("wanted secure flag %v, got: %v", srv.opts.CookieSecure, ckie.Secure)
316+
}
312317
}
313318

314319
func TestCheckDefaultDifficultyMatchesPolicy(t *testing.T) {

lib/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type Options struct {
4444
StripBasePrefix bool
4545
OpenGraph config.OpenGraph
4646
ServeRobotsTXT bool
47+
CookieSecure bool
4748
}
4849

4950
func LoadPoliciesOrDefault(ctx context.Context, fname string, defaultDifficulty int) (*policy.ParsedConfig, error) {

lib/http.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ import (
2323
var domainMatchRegexp = regexp.MustCompile(`^((xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$`)
2424

2525
type CookieOpts struct {
26-
Value string
27-
Host string
28-
Path string
29-
Name string
26+
Value string
27+
Host string
28+
Path string
29+
Name string
30+
Expiry time.Duration
3031
}
3132

3233
func (s *Server) SetCookie(w http.ResponseWriter, cookieOpts CookieOpts) {
@@ -45,12 +46,17 @@ func (s *Server) SetCookie(w http.ResponseWriter, cookieOpts CookieOpts) {
4546
}
4647
}
4748

49+
if cookieOpts.Expiry == 0 {
50+
cookieOpts.Expiry = s.opts.CookieExpiration
51+
}
52+
4853
http.SetCookie(w, &http.Cookie{
4954
Name: name,
5055
Value: cookieOpts.Value,
51-
Expires: time.Now().Add(s.opts.CookieExpiration),
52-
SameSite: http.SameSiteLaxMode,
56+
Expires: time.Now().Add(cookieOpts.Expiry),
57+
SameSite: http.SameSiteNoneMode,
5358
Domain: domain,
59+
Secure: s.opts.CookieSecure,
5460
Partitioned: s.opts.CookiePartitioned,
5561
Path: path,
5662
})
@@ -77,9 +83,10 @@ func (s *Server) ClearCookie(w http.ResponseWriter, cookieOpts CookieOpts) {
7783
Value: "",
7884
MaxAge: -1,
7985
Expires: time.Now().Add(-1 * time.Minute),
80-
SameSite: http.SameSiteLaxMode,
86+
SameSite: http.SameSiteNoneMode,
8187
Partitioned: s.opts.CookiePartitioned,
8288
Domain: domain,
89+
Secure: s.opts.CookieSecure,
8390
Path: path,
8491
})
8592
}
@@ -132,11 +139,12 @@ func (s *Server) RenderIndex(w http.ResponseWriter, r *http.Request, rule *polic
132139
}
133140
}
134141

135-
http.SetCookie(w, &http.Cookie{
136-
Name: anubis.TestCookieName,
137-
Value: challengeStr,
138-
Expires: time.Now().Add(30 * time.Minute),
139-
Path: "/",
142+
s.SetCookie(w, CookieOpts{
143+
Value: challengeStr,
144+
Host: r.Host,
145+
Path: "/",
146+
Name: anubis.TestCookieName,
147+
Expiry: 30 * time.Minute,
140148
})
141149

142150
impl, ok := challenge.Get(rule.Challenge.Algorithm)

0 commit comments

Comments
 (0)