From f6e077c9075aa29931563342ead712232babcfe8 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Sun, 31 Aug 2025 07:51:54 -0400 Subject: [PATCH] fix(challenge/metarefresh): ensure that clients have waited long enough (#1068) Some admins have noticed that clients are not waiting the right amount of time in order to access a resource protected by the metarefresh challenge. This patch adds a check to make sure that clients have waited at least 95% (difficulty times 950 milliseconds instead of difficulity times 1000 milliseconds) of the time they should. If this scales, maybe time is the best way to go for Anubis in the near future instead of anything else computational. Signed-off-by: Xe Iaso --- docs/docs/CHANGELOG.md | 3 ++- lib/challenge/metarefresh/metarefresh.go | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/docs/CHANGELOG.md b/docs/docs/CHANGELOG.md index 8bd209b..453d41a 100644 --- a/docs/docs/CHANGELOG.md +++ b/docs/docs/CHANGELOG.md @@ -15,7 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add a "proof of React" challenge to prove that the client is able to run a simple JSX app. - Added possibility to disable HTTP keep-alive to support backends not properly - handling it + handling it. +- Add a server-side check for the meta-refresh challenge that makes sure clients have waited for at least 95% of the time that they should. - Added a missing link to the Caddy installation environment in the installation documentation. - Downstream consumers can change the default [log/slog#Logger](https://pkg.go.dev/log/slog#Logger) instance that Anubis uses by setting `opts.Logger` to your slog instance of choice ([#864](https://github.com/TecharoHQ/anubis/issues/864)). - The [Thoth client](https://anubis.techaro.lol/docs/admin/thoth) is now public in the repo instead of being an internal package. diff --git a/lib/challenge/metarefresh/metarefresh.go b/lib/challenge/metarefresh/metarefresh.go index 7655a9d..5564ae2 100644 --- a/lib/challenge/metarefresh/metarefresh.go +++ b/lib/challenge/metarefresh/metarefresh.go @@ -5,6 +5,7 @@ import ( "fmt" "log/slog" "net/http" + "time" "github.com/TecharoHQ/anubis" "github.com/TecharoHQ/anubis/lib/challenge" @@ -42,6 +43,12 @@ func (i *Impl) Issue(r *http.Request, lg *slog.Logger, in *challenge.IssueInput) } func (i *Impl) Validate(r *http.Request, lg *slog.Logger, in *challenge.ValidateInput) error { + wantTime := in.Challenge.IssuedAt.Add(time.Duration(in.Rule.Challenge.Difficulty) * 950 * time.Millisecond) + + if time.Now().Before(wantTime) { + return challenge.NewError("validate", "insufficent time", fmt.Errorf("%w: wanted user to wait until at least %s", challenge.ErrFailed, wantTime.Format(time.RFC3339))) + } + gotChallenge := r.FormValue("challenge") if subtle.ConstantTimeCompare([]byte(in.Challenge.RandomData), []byte(gotChallenge)) != 1 {