mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-24 14:55:02 +03:00
fix(middleware): log rejected CSRF requests with the trusted client address (#6692)
A panel or API request rejected for a missing or wrong CSRF token got a bare 403 and left nothing in the log, so an operator chasing failed logins from a stale tab or a script had no trace. CSRFMiddleware now logs a warning with the method, path and client address. The address comes from getRemoteIp, which honours the trusted-proxy list, instead of gin's ClientIP, which trusts any peer's X-Forwarded-For.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/session"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -34,11 +35,9 @@ func newCSPNonce() string {
|
||||
return base64.RawStdEncoding.EncodeToString(b[:])
|
||||
}
|
||||
|
||||
// CSRFMiddleware rejects unsafe requests that do not include the session CSRF token.
|
||||
// Bearer-token-authenticated callers (api_authed flag set by APIController.checkAPIAuth)
|
||||
// short-circuit the CSRF check — they are not browser sessions, so the
|
||||
// cross-site request forgery threat model doesn't apply to them.
|
||||
func CSRFMiddleware() gin.HandlerFunc {
|
||||
// CSRFMiddleware rejects unsafe session requests lacking the CSRF token; bearer (api_authed) callers skip it.
|
||||
// clientIP must honour the trusted-proxy list: c.ClientIP trusts any peer's X-Forwarded-For.
|
||||
func CSRFMiddleware(clientIP func(*gin.Context) string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if c.GetBool("api_authed") {
|
||||
c.Next()
|
||||
@@ -49,6 +48,7 @@ func CSRFMiddleware() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
if !session.ValidateCSRFToken(c) {
|
||||
logger.Warningf("CSRF validation failed, request rejected: method=%s path=%s IP=%s", c.Request.Method, c.Request.URL.Path, clientIP(c))
|
||||
c.AbortWithStatus(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
func TestCSRFMiddlewareAllowsSafeMethods(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
router.Use(CSRFMiddleware())
|
||||
router.Use(CSRFMiddleware(func(*gin.Context) string { return "" }))
|
||||
router.GET("/safe", func(c *gin.Context) {
|
||||
c.String(http.StatusOK, "ok")
|
||||
})
|
||||
@@ -42,7 +42,7 @@ func TestCSRFMiddlewareRejectsMissingTokenAndAcceptsValidToken(t *testing.T) {
|
||||
}
|
||||
c.String(http.StatusOK, token)
|
||||
})
|
||||
router.POST("/submit", CSRFMiddleware(), func(c *gin.Context) {
|
||||
router.POST("/submit", CSRFMiddleware(func(*gin.Context) string { return "" }), func(c *gin.Context) {
|
||||
c.String(http.StatusOK, "ok")
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user