Add CSRF verification
This commit is contained in:
parent
e7cee4c448
commit
d11094481f
|
@ -18,6 +18,7 @@ import (
|
|||
)
|
||||
|
||||
const SessionCookieName = "HMNSession"
|
||||
const CSRFFieldName = "csrf_token"
|
||||
|
||||
const sessionDuration = time.Hour * 24 * 14
|
||||
|
||||
|
@ -97,7 +98,7 @@ func NewSessionCookie(session *models.Session) *http.Cookie {
|
|||
|
||||
Secure: config.Config.Auth.CookieSecure,
|
||||
HttpOnly: true,
|
||||
SameSite: http.SameSiteDefaultMode,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"git.handmade.network/hmn/hmn/src/auth"
|
||||
"git.handmade.network/hmn/hmn/src/hmnurl"
|
||||
"git.handmade.network/hmn/hmn/src/logging"
|
||||
"github.com/Masterminds/sprig"
|
||||
|
@ -113,7 +114,7 @@ var HMNTemplateFuncs = template.FuncMap{
|
|||
return template.CSS(color.HTML())
|
||||
},
|
||||
"csrftoken": func(s Session) template.HTML {
|
||||
return template.HTML(fmt.Sprintf(`<input type="hidden" name="csrf_token" value="%s">`, s.CSRFToken))
|
||||
return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`, auth.CSRFFieldName, s.CSRFToken))
|
||||
},
|
||||
"darken": func(amount float64, color noire.Color) noire.Color {
|
||||
return color.Shade(amount)
|
||||
|
|
|
@ -534,9 +534,20 @@ func ForumNewThread(c *RequestContext) ResponseData {
|
|||
baseData.MathjaxEnabled = true
|
||||
// TODO(ben): Set breadcrumbs
|
||||
|
||||
c.Perf.StartBlock("SQL", "Fetch category tree")
|
||||
categoryTree := models.GetFullCategoryTree(c.Context(), c.Conn)
|
||||
lineageBuilder := models.MakeCategoryLineageBuilder(categoryTree)
|
||||
c.Perf.EndBlock()
|
||||
|
||||
currentCatId, valid := validateSubforums(lineageBuilder, c.CurrentProject, c.PathParams["cats"])
|
||||
if !valid {
|
||||
return FourOhFour(c)
|
||||
}
|
||||
|
||||
var res ResponseData
|
||||
err := res.WriteTemplate("editor.html", editorData{
|
||||
BaseData: baseData,
|
||||
SubmitUrl: hmnurl.BuildForumNewThread(c.CurrentProject.Slug, lineageBuilder.GetSubforumLineageSlugs(currentCatId), true),
|
||||
SubmitLabel: "Post New Thread",
|
||||
PreviewLabel: "Preview",
|
||||
}, c.Perf)
|
||||
|
@ -556,8 +567,7 @@ func ForumNewThread(c *RequestContext) ResponseData {
|
|||
}
|
||||
|
||||
func ForumNewThreadSubmit(c *RequestContext) ResponseData {
|
||||
var res ResponseData
|
||||
return res
|
||||
return c.Redirect(hmnurl.BuildForumNewThread(models.HMNProjectSlug, nil, false), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func validateSubforums(lineageBuilder *models.CategoryLineageBuilder, project *models.Project, catPath string) (int, bool) {
|
||||
|
|
|
@ -90,6 +90,30 @@ func NewWebsiteRoutes(conn *pgxpool.Pool, perfCollector *perf.PerfCollector) htt
|
|||
}
|
||||
}
|
||||
|
||||
csrfMiddleware := func(h Handler) Handler {
|
||||
// CSRF mitigation actions per the OWASP cheat sheet:
|
||||
// https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html
|
||||
return func(c *RequestContext) ResponseData {
|
||||
c.Req.ParseForm()
|
||||
csrfToken := c.Req.Form.Get(auth.CSRFFieldName)
|
||||
if csrfToken != c.CurrentSession.CSRFToken {
|
||||
c.Logger.Warn().Str("userId", c.CurrentUser.Username).Msg("user failed CSRF validation - potential attack?")
|
||||
|
||||
err := auth.DeleteSession(c.Context(), c.Conn, c.CurrentSession.ID)
|
||||
if err != nil {
|
||||
c.Logger.Error().Err(err).Msg("failed to delete session on CSRF failure")
|
||||
}
|
||||
|
||||
res := c.Redirect("/", http.StatusSeeOther)
|
||||
res.SetCookie(auth.DeleteSessionCookie)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
return h(c)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(asaf): login/logout shouldn't happen on subdomains. We should verify that in the middleware.
|
||||
routes.POST(hmnurl.RegexLoginAction, Login)
|
||||
routes.GET(hmnurl.RegexLogoutAction, Logout)
|
||||
|
@ -124,7 +148,7 @@ func NewWebsiteRoutes(conn *pgxpool.Pool, perfCollector *perf.PerfCollector) htt
|
|||
|
||||
// NOTE(asaf): Any-project routes:
|
||||
mainRoutes.Handle([]string{http.MethodGet, http.MethodPost}, hmnurl.RegexForumNewThread, authMiddleware(ForumNewThread))
|
||||
mainRoutes.POST(hmnurl.RegexForumNewThreadSubmit, authMiddleware(ForumNewThreadSubmit))
|
||||
mainRoutes.POST(hmnurl.RegexForumNewThreadSubmit, authMiddleware(csrfMiddleware(ForumNewThreadSubmit)))
|
||||
mainRoutes.GET(hmnurl.RegexForumThread, ForumThread)
|
||||
mainRoutes.GET(hmnurl.RegexForumCategory, ForumCategory)
|
||||
mainRoutes.GET(hmnurl.RegexForumPost, ForumPostRedirect)
|
||||
|
|
Loading…
Reference in New Issue