Rate limit login attempts using a Sliding Window counter rate-limiter

This commit is contained in:
Deluan 2020-07-19 14:45:05 -04:00
parent feca030c6d
commit f0160f5d2a
4 changed files with 23 additions and 2 deletions

View File

@ -34,6 +34,8 @@ type configOptions struct {
CoverJpegQuality int
UIWelcomeMessage string
GATrackingID string
AuthRequestLimit int
AuthWindowLength time.Duration
// DevFlags. These are used to enable/disable debugging and incomplete features
DevLogSourceLine bool
@ -83,7 +85,7 @@ func init() {
viper.SetDefault("transcodingcachesize", "100MB")
viper.SetDefault("imagecachesize", "100MB")
// Config options only valid for file configuration
// Config options only valid for file/env configuration
viper.SetDefault("ignoredarticles", "The El La Los Las Le Les Os As O A")
viper.SetDefault("indexgroups", "A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ) [Unknown]([)")
viper.SetDefault("probecommand", "ffmpeg %s -f ffmetadata")
@ -91,6 +93,8 @@ func init() {
viper.SetDefault("coverjpegquality", 75)
viper.SetDefault("uiwelcomemessage", "")
viper.SetDefault("gatrackingid", "")
viper.SetDefault("authrequestlimit", 5)
viper.SetDefault("authwindowlength", 20*time.Second)
// DevFlags. These are used to enable/disable debugging and incomplete features
viper.SetDefault("devlogsourceline", false)

1
go.mod
View File

@ -14,6 +14,7 @@ require (
github.com/dustin/go-humanize v1.0.0
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/cors v1.1.1
github.com/go-chi/httprate v0.4.0
github.com/go-chi/jwtauth v4.0.4+incompatible
github.com/google/uuid v1.1.1
github.com/google/wire v0.4.0

3
go.sum
View File

@ -45,6 +45,7 @@ github.com/bradleyjkemp/cupaloy v2.3.0+incompatible h1:UafIjBvWQmS9i/xRg+CamMrnL
github.com/bradleyjkemp/cupaloy v2.3.0+incompatible/go.mod h1:Au1Xw1sgaJ5iSFktEhYsS0dbQiS1B0/XMXl+42y9Ilk=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -97,6 +98,8 @@ github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyN
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/cors v1.1.1 h1:eHuqxsIw89iXcWnWUN8R72JMibABJTN/4IOYI5WERvw=
github.com/go-chi/cors v1.1.1/go.mod h1:K2Yje0VW/SJzxiyMYu6iPQYa7hMjQX2i/F491VChg1I=
github.com/go-chi/httprate v0.4.0 h1:M2qVV0w6ksgLs6L8lTrvqNeaVm0ZJNVdbYM8u2T8HaE=
github.com/go-chi/httprate v0.4.0/go.mod h1:7e7qjQtHzEbdyW5TYQrl4X2uNRCnlTajictc7B4ftgc=
github.com/go-chi/jwtauth v4.0.4+incompatible h1:LGIxg6YfvSBzxU2BljXbrzVc1fMlgqSKBQgKOGAVtPY=
github.com/go-chi/jwtauth v4.0.4+incompatible/go.mod h1:Q5EIArY/QnD6BdS+IyDw7B2m6iNbnPxtfd6/BcmtWbs=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=

View File

@ -9,9 +9,11 @@ import (
"github.com/deluan/navidrome/assets"
"github.com/deluan/navidrome/conf"
"github.com/deluan/navidrome/core/auth"
"github.com/deluan/navidrome/log"
"github.com/deluan/navidrome/model"
"github.com/deluan/rest"
"github.com/go-chi/chi"
"github.com/go-chi/httprate"
"github.com/go-chi/jwtauth"
)
@ -35,7 +37,18 @@ func (app *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (app *Router) routes(path string) http.Handler {
r := chi.NewRouter()
r.Post("/login", Login(app.ds))
if conf.Server.AuthRequestLimit > 0 {
log.Info(context.TODO(), "Login rate limit set", "requestLimit", conf.Server.AuthRequestLimit,
"windowLength", conf.Server.AuthWindowLength)
rateLimiter := httprate.LimitByIP(conf.Server.AuthRequestLimit, conf.Server.AuthWindowLength)
r.With(rateLimiter).Post("/login", Login(app.ds))
} else {
log.Warn(context.TODO(), "Login rate limit is disabled! Consider enabling it to be protected against brute-force attacks")
r.Post("/login", Login(app.ds))
}
r.Post("/createAdmin", CreateAdmin(app.ds))
r.Route("/api", func(r chi.Router) {