diff options
| author | William Hergès <william@herges.fr> | 2026-01-02 19:02:15 +0100 |
|---|---|---|
| committer | William Hergès <william@herges.fr> | 2026-01-02 19:02:15 +0100 |
| commit | 7f4bd0e1620cf1c5c66ef30f8c44d2d5adc659ee (patch) | |
| tree | 8cd3e79b9304b76c37b12f2d65b1451c700e33ad | |
| parent | 7d4ec713ba76d7e787c9d787a38a96b81daf52dc (diff) | |
feat(backend): rate limit dumb attacker bot
| -rw-r--r-- | backend/data.go | 3 | ||||
| -rw-r--r-- | backend/router.go | 33 | ||||
| -rw-r--r-- | backend/storage/stats.go | 8 |
3 files changed, 36 insertions, 8 deletions
diff --git a/backend/data.go b/backend/data.go index 3a8acf0..f7ba3b1 100644 --- a/backend/data.go +++ b/backend/data.go @@ -69,9 +69,6 @@ func (d *data) merge(cfg *Config, r *http.Request) { d.Image = cfg.DefaultImage } if d.URL == "" { - if !strings.HasPrefix(r.URL.Path, "/") { - r.URL.Path = "/" + r.URL.Path - } d.URL = r.URL.Path } if d.Language == "" { diff --git a/backend/router.go b/backend/router.go index f4b5763..48ffe0a 100644 --- a/backend/router.go +++ b/backend/router.go @@ -12,6 +12,7 @@ import ( "net/http" "os" "path" + "regexp" "strings" "time" @@ -89,6 +90,12 @@ func NewRouter(debug bool, cfg *Config, db *sql.DB, assets fs.FS) *chi.Mux { } r.Use(func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !strings.HasPrefix(r.RequestURI, "/") { + r.RequestURI = "/" + r.RequestURI + } + if !strings.HasPrefix(r.URL.Path, "/") { + r.URL.Path = "/" + r.URL.Path + } next.ServeHTTP(w, r.WithContext( setContext(r.Context(), r), )) @@ -146,8 +153,21 @@ func NewRouter(debug bool, cfg *Config, db *sql.DB, assets fs.FS) *chi.Mux { }(r.Context(), r) }) }) + // anti dumb attackers bot + phpUri := regexp.MustCompile(`/.+\.php(/.*)?`) + dotUri := regexp.MustCompile(`/(.*/)*\..*`) + r.Use(func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if phpUri.MatchString(r.RequestURI) || dotUri.MatchString(r.RequestURI) { + handleSus(w, r) + return + } + next.ServeHTTP(w, r) + }) + }) - r.HandleFunc("/{file:[a-z]+}.txt", func(w http.ResponseWriter, r *http.Request) { + // txt files + r.Get("/{file:[a-z]+}.txt", func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() cfg := ctx.Value(configKey).(*Config) logger := GetLogger(ctx) @@ -168,6 +188,17 @@ func NewRouter(debug bool, cfg *Config, db *sql.DB, assets fs.FS) *chi.Mux { return r } +func handleSus(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + logger := GetLogger(ctx) + logger.Warn("sus request", "User-Agent", r.Header.Get("User-Agent")) + if rateLimit(ctx) { + http.Error(w, "Too many requests", http.StatusTooManyRequests) + return + } + notFound(w, r) +} + // httpEmbedFS is an implementation of fs.FS, fs.ReadDirFS and fs.ReadFileFS helping to manage embed.FS for http server type httpEmbedFS struct { embed.FS diff --git a/backend/storage/stats.go b/backend/storage/stats.go index 345164e..f40c060 100644 --- a/backend/storage/stats.go +++ b/backend/storage/stats.go @@ -57,14 +57,11 @@ const HumanPageLoad = "/assets/styles.css" func UpdateStats(ctx context.Context, r *http.Request, domain string) error { target := r.URL.Path - if !strings.HasPrefix(target, "/") { - target = "/" + target - } if strings.HasPrefix(target, "/admin") { return nil } ref := r.Header.Get("Referer") - if ref == "" { + if len(ref) == 0 { return nil } refUrl, err := url.Parse(ref) @@ -72,6 +69,9 @@ func UpdateStats(ctx context.Context, r *http.Request, domain string) error { return nil } ref = refUrl.Host + if len(ref) == 0 { + return nil + } if ref == domain || ref == fmt.Sprintf("localhost:%d", 8000) { ref = refUrl.Path if !strings.HasPrefix(ref, "/") { |
