From 1d2f4e8a5b86a5bacd5fe2d6c25026dbaf3ba460 Mon Sep 17 00:00:00 2001 From: WeebDataHoarder Date: Sun, 4 May 2025 20:21:53 +0200 Subject: [PATCH] challenge/context: use additional HTTP headers in challenge key generation if the challenge allows for it --- lib/challenge/data.go | 3 +++ lib/challenge/key.go | 16 ++++++------- lib/challenge/preload-link/preload-link.go | 3 +++ lib/challenge/register.go | 28 +++++++++++++++++++--- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/lib/challenge/data.go b/lib/challenge/data.go index bb4936e..37faa4d 100644 --- a/lib/challenge/data.go +++ b/lib/challenge/data.go @@ -329,6 +329,9 @@ func (d *RequestData) ResponseHeaders(w http.ResponseWriter) { //w.Header().Set("Accept-CH", "Sec-CH-UA, Sec-CH-UA-Platform") //w.Header().Set("Critical-CH", "Sec-CH-UA, Sec-CH-UA-Platform") + // send Vary header to mark that response may vary based on Cookie values and other client headers + w.Header().Set("Vary", "Cookie, Accept, Accept-Encoding, Accept-Language, User-Agent") + if d.State.Settings().MainName != "" { w.Header().Add("Via", fmt.Sprintf("%s %s@%s", d.r.Proto, d.State.Settings().MainName, d.State.Settings().MainVersion)) } diff --git a/lib/challenge/key.go b/lib/challenge/key.go index 6574246..d862918 100644 --- a/lib/challenge/key.go +++ b/lib/challenge/key.go @@ -52,15 +52,13 @@ func GetChallengeKeyForRequest(state StateInterface, reg *Registration, until ti hasher.Write([]byte{0}) // specific headers - for _, k := range []string{ - "Accept-Language", - // General browser information - "User-Agent", - // TODO: not sent in preload - //"Sec-Ch-Ua", - //"Sec-Ch-Ua-Platform", - } { - hasher.Write([]byte(r.Header.Get(k))) + for _, k := range reg.KeyHeaders { + hasher.Write([]byte(k)) + hasher.Write([]byte{0}) + for _, v := range r.Header.Values(k) { + hasher.Write([]byte(v)) + hasher.Write([]byte{1}) + } hasher.Write([]byte{0}) } hasher.Write([]byte{0}) diff --git a/lib/challenge/preload-link/preload-link.go b/lib/challenge/preload-link/preload-link.go index 1acac99..b86df30 100644 --- a/lib/challenge/preload-link/preload-link.go +++ b/lib/challenge/preload-link/preload-link.go @@ -44,6 +44,9 @@ func FillRegistration(state challenge.StateInterface, reg *challenge.Registratio reg.Class = challenge.ClassTransparent + // some of regular headers are not sent in default headers + reg.KeyHeaders = challenge.MinimalKeyHeaders + ob := challenge.NewAwaiter[string]() reg.Object = ob diff --git a/lib/challenge/register.go b/lib/challenge/register.go index 25f8ad1..7707a5b 100644 --- a/lib/challenge/register.go +++ b/lib/challenge/register.go @@ -35,6 +35,24 @@ var idCounter Id // DefaultDuration TODO: adjust const DefaultDuration = time.Hour * 24 * 7 +var DefaultKeyHeaders = []string{ + // General browser information + "User-Agent", + // Accept headers + "Accept-Language", + "Accept-Encoding", + + // NOTE: not sent in preload + "Sec-Ch-Ua", + "Sec-Ch-Ua-Platform", +} + +var MinimalKeyHeaders = []string{ + "Accept-Language", + // General browser information + "User-Agent", +} + func (r Register) Create(state StateInterface, name string, pol policy.Challenge, replacer *strings.Replacer) (*Registration, Id, error) { runtime, ok := Runtimes[pol.Runtime] if !ok { @@ -42,9 +60,10 @@ func (r Register) Create(state StateInterface, name string, pol policy.Challenge } reg := &Registration{ - Name: name, - Path: path.Join(state.UrlPath(), "challenge", name), - Duration: pol.Duration, + Name: name, + Path: path.Join(state.UrlPath(), "challenge", name), + Duration: pol.Duration, + KeyHeaders: DefaultKeyHeaders, } if reg.Duration == 0 { @@ -126,6 +145,9 @@ type Registration struct { Verify VerifyFunc VerifyProbability float64 + // KeyHeaders The client headers used in key generation, in this order + KeyHeaders []string + // IssueChallenge Issues a challenge to a request. // If Class is ClassTransparent and VerifyResult is !VerifyResult.Ok(), continue with other challenges // TODO: have this return error as well