Added security timer middleware

This commit is contained in:
Asaf Gartner 2021-08-17 09:08:33 +03:00
parent 40ba0d5455
commit c913b58e4c
3 changed files with 19 additions and 6 deletions

View File

@ -161,7 +161,6 @@ func RegisterNewUserSubmit(c *RequestContext) ResponseData {
blacklisted := false
if blacklisted {
// NOTE(asaf): Silent rejection so we don't allow attackers to harvest emails.
time.Sleep(time.Second * 3) // NOTE(asaf): Pretend to send email
return c.Redirect(hmnurl.BuildRegistrationSuccess(), http.StatusSeeOther)
}
c.Perf.EndBlock()
@ -208,7 +207,6 @@ func RegisterNewUserSubmit(c *RequestContext) ResponseData {
if emailAlreadyExists {
// NOTE(asaf): Silent rejection so we don't allow attackers to harvest emails.
time.Sleep(time.Second * 3) // NOTE(asaf): Pretend to send email
return c.Redirect(hmnurl.BuildRegistrationSuccess(), http.StatusSeeOther)
}

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"html/template"
"math/rand"
"net/http"
"net/url"
"strings"
@ -19,11 +20,12 @@ import (
"git.handmade.network/hmn/hmn/src/oops"
"git.handmade.network/hmn/hmn/src/perf"
"git.handmade.network/hmn/hmn/src/templates"
"git.handmade.network/hmn/hmn/src/utils"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/teacat/noire"
)
func NewWebsiteRoutes(conn *pgxpool.Pool, perfCollector *perf.PerfCollector) http.Handler {
func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, perfCollector *perf.PerfCollector) http.Handler {
router := &Router{}
routes := RouteBuilder{
Router: router,
@ -121,6 +123,16 @@ func NewWebsiteRoutes(conn *pgxpool.Pool, perfCollector *perf.PerfCollector) htt
}
}
securityTimerMiddleware := func(delayMs int, h Handler) Handler {
// NOTE(asaf): Will make sure that the request takes at least `delayMs` to finish. Adds a 10% random duration.
return func(c *RequestContext) ResponseData {
duration := time.Millisecond * time.Duration(delayMs+rand.Intn(utils.IntMax(1, delayMs/10)))
res := h(c)
utils.SleepContext(longRequestContext, duration)
return res
}
}
routes.GET(hmnurl.RegexPublic, func(c *RequestContext) ResponseData {
var res ResponseData
http.StripPrefix("/public/", http.FileServer(http.Dir("public"))).ServeHTTP(&res, c.Req)
@ -152,14 +164,14 @@ func NewWebsiteRoutes(conn *pgxpool.Pool, perfCollector *perf.PerfCollector) htt
mainRoutes.GET(hmnurl.RegexLoginPage, LoginPage)
mainRoutes.GET(hmnurl.RegexRegister, RegisterNewUser)
mainRoutes.POST(hmnurl.RegexRegister, RegisterNewUserSubmit)
mainRoutes.POST(hmnurl.RegexRegister, securityTimerMiddleware(3000, RegisterNewUserSubmit))
mainRoutes.GET(hmnurl.RegexRegistrationSuccess, RegisterNewUserSuccess)
mainRoutes.GET(hmnurl.RegexOldEmailConfirmation, EmailConfirmation) // TODO(asaf): Delete this a bit after launch
mainRoutes.GET(hmnurl.RegexEmailConfirmation, EmailConfirmation)
mainRoutes.POST(hmnurl.RegexEmailConfirmation, EmailConfirmationSubmit)
mainRoutes.GET(hmnurl.RegexRequestPasswordReset, RequestPasswordReset)
mainRoutes.POST(hmnurl.RegexRequestPasswordReset, RequestPasswordResetSubmit)
mainRoutes.POST(hmnurl.RegexRequestPasswordReset, securityTimerMiddleware(3000, RequestPasswordResetSubmit))
mainRoutes.GET(hmnurl.RegexPasswordResetSent, PasswordResetSent)
mainRoutes.GET(hmnurl.RegexOldDoPasswordReset, DoPasswordReset)
mainRoutes.GET(hmnurl.RegexDoPasswordReset, DoPasswordReset)

View File

@ -30,13 +30,14 @@ var WebsiteCommand = &cobra.Command{
logging.Info().Msg("Hello, HMN!")
backgroundJobContext, cancelBackgroundJobs := context.WithCancel(context.Background())
longRequestContext, cancelLongRequests := context.WithCancel(context.Background())
conn := db.NewConnPool(config.Config.Postgres.MinConn, config.Config.Postgres.MaxConn)
perfCollector := perf.RunPerfCollector(backgroundJobContext)
server := http.Server{
Addr: config.Config.Addr,
Handler: NewWebsiteRoutes(conn, perfCollector),
Handler: NewWebsiteRoutes(longRequestContext, conn, perfCollector),
}
backgroundJobsDone := zipJobs(
@ -52,6 +53,8 @@ var WebsiteCommand = &cobra.Command{
<-signals
logging.Info().Msg("Shutting down the website")
go func() {
logging.Info().Msg("cancelling long requests")
cancelLongRequests()
timeout, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
logging.Info().Msg("shutting down web server")