[MM-10346] CSRF Token Implementation + Tests (#10067)
* CSRF Token Implementation + Tests Remove debug statements Implement requested changes * Fix non-cookie authentication methods stripping auth data from requests * Fail when CSRF cookie is not returned as part of login
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
86aa01cf36
Коммит
7cc66ee1d4
@@ -278,6 +278,7 @@ func (a *App) trackConfig() {
|
||||
"allow_cookies_for_subdomains": *cfg.ServiceSettings.AllowCookiesForSubdomains,
|
||||
"enable_api_team_deletion": *cfg.ServiceSettings.EnableAPITeamDeletion,
|
||||
"experimental_enable_hardened_mode": *cfg.ServiceSettings.ExperimentalEnableHardenedMode,
|
||||
"experimental_strict_csrf_enforcement": *cfg.ServiceSettings.ExperimentalStrictCSRFEnforcement,
|
||||
"enable_email_invitations": *cfg.ServiceSettings.EnableEmailInvitations,
|
||||
"experimental_channel_organization": *cfg.ServiceSettings.ExperimentalChannelOrganization,
|
||||
"experimental_ldap_group_sync": *cfg.ServiceSettings.ExperimentalLdapGroupSync,
|
||||
|
||||
11
app/login.go
11
app/login.go
@@ -189,8 +189,19 @@ func (a *App) DoLogin(w http.ResponseWriter, r *http.Request, user *model.User,
|
||||
Secure: secure,
|
||||
}
|
||||
|
||||
csrfCookie := &http.Cookie{
|
||||
Name: model.SESSION_COOKIE_CSRF,
|
||||
Value: session.GetCSRF(),
|
||||
Path: "/",
|
||||
MaxAge: maxAge,
|
||||
Expires: expiresAt,
|
||||
Domain: domain,
|
||||
Secure: secure,
|
||||
}
|
||||
|
||||
http.SetCookie(w, sessionCookie)
|
||||
http.SetCookie(w, userCookie)
|
||||
http.SetCookie(w, csrfCookie)
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
@@ -65,21 +65,34 @@ func (a *App) servePluginRequest(w http.ResponseWriter, r *http.Request, handler
|
||||
r.Header.Del("Mattermost-User-Id")
|
||||
if token != "" {
|
||||
session, err := a.GetSession(token)
|
||||
csrfCheckPassed := true
|
||||
csrfCheckPassed := false
|
||||
|
||||
if err == nil && cookieAuth && r.Method != "GET" && r.Header.Get(model.HEADER_REQUESTED_WITH) != model.HEADER_REQUESTED_WITH_XML {
|
||||
bodyBytes, _ := ioutil.ReadAll(r.Body)
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
r.ParseForm()
|
||||
sentToken := r.FormValue("csrf")
|
||||
expectedToken := session.GetCSRF()
|
||||
if err == nil && cookieAuth && r.Method != "GET" {
|
||||
sentToken := ""
|
||||
|
||||
if sentToken != expectedToken {
|
||||
csrfCheckPassed = false
|
||||
if r.Header.Get(model.HEADER_CSRF_TOKEN) == "" {
|
||||
bodyBytes, _ := ioutil.ReadAll(r.Body)
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
r.ParseForm()
|
||||
sentToken = r.FormValue("csrf")
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
} else {
|
||||
sentToken = r.Header.Get(model.HEADER_CSRF_TOKEN)
|
||||
}
|
||||
|
||||
// Set Request Body again, since otherwise form values aren't accessible in plugin handler
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
expectedToken := session.GetCSRF()
|
||||
|
||||
if sentToken == expectedToken {
|
||||
csrfCheckPassed = true
|
||||
}
|
||||
|
||||
// ToDo(DSchalla) 2019/01/04: Remove after deprecation period and only allow CSRF Header (MM-13657)
|
||||
if !*a.Config().ServiceSettings.ExperimentalStrictCSRFEnforcement && r.Header.Get(model.HEADER_REQUESTED_WITH) == model.HEADER_REQUESTED_WITH_XML && !csrfCheckPassed {
|
||||
a.Log.Warn("CSRF Check failed for request - Please migrate your plugin to either send a CSRF Header or Form Field, XMLHttpRequest is deprecated")
|
||||
csrfCheckPassed = true
|
||||
}
|
||||
} else {
|
||||
csrfCheckPassed = true
|
||||
}
|
||||
|
||||
if session != nil && err == nil && csrfCheckPassed {
|
||||
|
||||
Ссылка в новой задаче
Block a user