1
0

security.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. package middleware
  2. import (
  3. "crypto/rand"
  4. "encoding/base64"
  5. "net/http"
  6. "github.com/mhsanaei/3x-ui/v3/web/session"
  7. "github.com/gin-gonic/gin"
  8. )
  9. // SecurityHeadersMiddleware adds browser hardening headers to panel responses.
  10. func SecurityHeadersMiddleware(directHTTPS bool) gin.HandlerFunc {
  11. return func(c *gin.Context) {
  12. nonce := newCSPNonce()
  13. c.Set("csp_nonce", nonce)
  14. c.Header("X-Content-Type-Options", "nosniff")
  15. c.Header("X-Frame-Options", "DENY")
  16. c.Header("Referrer-Policy", "no-referrer")
  17. c.Header("Content-Security-Policy", "default-src 'self'; script-src 'self' 'nonce-"+nonce+"'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'")
  18. if directHTTPS {
  19. c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
  20. }
  21. c.Next()
  22. }
  23. }
  24. func newCSPNonce() string {
  25. var b [16]byte
  26. if _, err := rand.Read(b[:]); err != nil {
  27. return ""
  28. }
  29. return base64.RawStdEncoding.EncodeToString(b[:])
  30. }
  31. // CSRFMiddleware rejects unsafe requests that do not include the session CSRF token.
  32. // Bearer-token-authenticated callers (api_authed flag set by APIController.checkAPIAuth)
  33. // short-circuit the CSRF check — they are not browser sessions, so the
  34. // cross-site request forgery threat model doesn't apply to them.
  35. func CSRFMiddleware() gin.HandlerFunc {
  36. return func(c *gin.Context) {
  37. if c.GetBool("api_authed") {
  38. c.Next()
  39. return
  40. }
  41. if isSafeMethod(c.Request.Method) {
  42. c.Next()
  43. return
  44. }
  45. if !session.ValidateCSRFToken(c) {
  46. c.AbortWithStatus(http.StatusForbidden)
  47. return
  48. }
  49. c.Next()
  50. }
  51. }
  52. func isSafeMethod(method string) bool {
  53. switch method {
  54. case http.MethodGet, http.MethodHead, http.MethodOptions, http.MethodTrace:
  55. return true
  56. default:
  57. return false
  58. }
  59. }