mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-24 23:05:01 +03:00
3051aebb28
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.
42 lines
1.1 KiB
Go
42 lines
1.1 KiB
Go
package controller
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gin-contrib/sessions"
|
|
"github.com/gin-contrib/sessions/cookie"
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/logger"
|
|
)
|
|
|
|
func TestLoginCSRFRejectionLogsPeerIPNotForwardedHeader(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
engine := gin.New()
|
|
engine.Use(sessions.Sessions("3x-ui", cookie.NewStore([]byte("csrf-log-test-secret"))))
|
|
NewIndexController(engine.Group("/"))
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/login", nil)
|
|
req.RemoteAddr = "198.51.100.9:40000"
|
|
req.Header.Set("X-Forwarded-For", "203.0.113.66")
|
|
rec := httptest.NewRecorder()
|
|
engine.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusForbidden {
|
|
t.Fatalf("status = %d, want %d", rec.Code, http.StatusForbidden)
|
|
}
|
|
|
|
var line string
|
|
for _, l := range logger.GetLogs(50, "WARNING") {
|
|
if strings.Contains(l, "CSRF validation failed") {
|
|
line = l
|
|
break
|
|
}
|
|
}
|
|
if !strings.Contains(line, "IP=198.51.100.9") || strings.Contains(line, "203.0.113.66") {
|
|
t.Fatalf("CSRF rejection log = %q, want the untrusted peer 198.51.100.9 and not the forwarded header", line)
|
|
}
|
|
}
|