Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 12, 17:00 UTC
reverseproxy: cookie should be Secure and SameSite=None when TLS (#6115)
* reverseproxy: cookie should be Secure and SameSite=None when TLS * Update modules/caddyhttp/reverseproxy/selectionpolicies_test.go Co-authored-by: Mohammed Al Sahaf <mohammed@caffeinatedwonders.com> --------- Co-authored-by: Mohammed Al Sahaf <mohammed@caffeinatedwonders.com>
Sam Ottenhoff committed
Feb 23, 2024 at 14:45 UTC
da6a569e859f4dfbbebfd084060e15d940de8861
2 files changed
+66
-2
modules/caddyhttp/reverseproxy/selectionpolicies.go
+12
-2
@@ -655,12 +655,22 @@ func (s CookieHashSelection) Select(pool UpstreamPool, req *http.Request, w http
655
if err != nil {
656
return upstream
657
}
658
- http.SetCookie(w, &http.Cookie{
658
+ cookie := &http.Cookie{
659
Name: s.Name,
660
Value: sha,
661
Path: "/",
662
Secure: false,
663
- })
663
+ }
664
+ isProxyHttps := false
665
+ if trusted, ok := caddyhttp.GetVar(req.Context(), caddyhttp.TrustedProxyVarKey).(bool); ok && trusted {
666
+ xfp, xfpOk, _ := lastHeaderValue(req.Header, "X-Forwarded-Proto")
667
+ isProxyHttps = xfpOk && xfp == "https"
668
+ }
669
+ if req.TLS != nil || isProxyHttps {
670
+ cookie.Secure = true
671
+ cookie.SameSite = http.SameSiteNoneMode
672
+ }
673
+ http.SetCookie(w, cookie)
674
return upstream
675
}
676
modules/caddyhttp/reverseproxy/selectionpolicies_test.go
+54
@@ -658,6 +658,9 @@ func TestCookieHashPolicy(t *testing.T) {
658
if cookieServer1.Name != "lb" {
659
t.Error("cookieHashPolicy should set a cookie with name lb")
660
}
661
+ if cookieServer1.Secure {
662
+ t.Error("cookieHashPolicy should set cookie Secure attribute to false when request is not secure")
663
+ }
664
if h != pool[0] {
665
t.Error("Expected cookieHashPolicy host to be the first only available host.")
666
}
@@ -687,6 +690,57 @@ func TestCookieHashPolicy(t *testing.T) {
690
}
691
}
692
693
+func TestCookieHashPolicyWithSecureRequest(t *testing.T) {
694
+ ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
695
+ defer cancel()
696
+ cookieHashPolicy := CookieHashSelection{}
697
+ if err := cookieHashPolicy.Provision(ctx); err != nil {
698
+ t.Errorf("Provision error: %v", err)
699
+ t.FailNow()
700
+ }
701
+
702
+ pool := testPool()
703
+ pool[0].Dial = "localhost:8080"
704
+ pool[1].Dial = "localhost:8081"
705
+ pool[2].Dial = "localhost:8082"
706
+ pool[0].setHealthy(true)
707
+ pool[1].setHealthy(false)
708
+ pool[2].setHealthy(false)
709
+
710
+ // Create a test server that serves HTTPS requests
711
+ ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
712
+ h := cookieHashPolicy.Select(pool, r, w)
713
+ if h != pool[0] {
714
+ t.Error("Expected cookieHashPolicy host to be the first only available host.")
715
+ }
716
+ }))
717
+ defer ts.Close()
718
+
719
+ // Make a new HTTPS request to the test server
720
+ client := ts.Client()
721
+ request, err := http.NewRequest(http.MethodGet, ts.URL+"/test", nil)
722
+ if err != nil {
723
+ t.Fatal(err)
724
+ }
725
+ response, err := client.Do(request)
726
+ if err != nil {
727
+ t.Fatal(err)
728
+ }
729
+
730
+ // Check if the cookie set is Secure and has SameSiteNone mode
731
+ cookies := response.Cookies()
732
+ if len(cookies) == 0 {
733
+ t.Fatal("Expected a cookie to be set")
734
+ }
735
+ cookie := cookies[0]
736
+ if !cookie.Secure {
737
+ t.Error("Expected cookie Secure attribute to be true when request is secure")
738
+ }
739
+ if cookie.SameSite != http.SameSiteNoneMode {
740
+ t.Error("Expected cookie SameSite attribute to be None when request is secure")
741
+ }
742
+}
743
+
744
func TestCookieHashPolicyWithFirstFallback(t *testing.T) {
745
ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
746
defer cancel()