Implement CSRF protection and security hardening across the application (#4179)
* Implement CSRF protection and security hardening across the application - Added CSRF token handling in axios requests and HTML templates. - Introduced CSRF middleware to validate tokens for unsafe HTTP methods. - Implemented login limiter to prevent brute-force attacks. - Enhanced security headers in middleware for improved response security. - Updated login notification to include safe metadata without passwords. - Added tests for CSRF middleware and login limiter functionality. * fix
This commit is contained in:
committed by
GitHub
parent
a1b2382877
commit
10ebc6cbdc
@@ -0,0 +1,55 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const csrfTokenKey = "CSRF_TOKEN"
|
||||
|
||||
// CSRFHeaderName is the request header used by browser clients for unsafe methods.
|
||||
const CSRFHeaderName = "X-CSRF-Token"
|
||||
|
||||
// EnsureCSRFToken returns the current session CSRF token or creates one.
|
||||
func EnsureCSRFToken(c *gin.Context) (string, error) {
|
||||
s := sessions.Default(c)
|
||||
if token, ok := s.Get(csrfTokenKey).(string); ok && token != "" {
|
||||
return token, nil
|
||||
}
|
||||
token, err := newCSRFToken()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s.Set(csrfTokenKey, token)
|
||||
return token, s.Save()
|
||||
}
|
||||
|
||||
// ValidateCSRFToken checks the submitted CSRF token against the session token.
|
||||
func ValidateCSRFToken(c *gin.Context) bool {
|
||||
s := sessions.Default(c)
|
||||
expected, ok := s.Get(csrfTokenKey).(string)
|
||||
if !ok || expected == "" {
|
||||
return false
|
||||
}
|
||||
actual := c.GetHeader(CSRFHeaderName)
|
||||
if actual == "" {
|
||||
actual = c.PostForm("_csrf")
|
||||
}
|
||||
if len(actual) != len(expected) {
|
||||
return false
|
||||
}
|
||||
return subtle.ConstantTimeCompare([]byte(actual), []byte(expected)) == 1
|
||||
}
|
||||
|
||||
func newCSRFToken() (string, error) {
|
||||
buf := make([]byte, 32)
|
||||
if _, err := io.ReadFull(rand.Reader, buf); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(buf), nil
|
||||
}
|
||||
@@ -73,6 +73,7 @@ func ClearSession(c *gin.Context) error {
|
||||
Path: cookiePath,
|
||||
MaxAge: -1,
|
||||
HttpOnly: true,
|
||||
Secure: c.Request.TLS != nil,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
})
|
||||
return s.Save()
|
||||
|
||||
Reference in New Issue
Block a user