This commit is contained in:
2025-08-26 19:15:37 -04:00
parent 7ca61eb712
commit 86900b0bd4
16 changed files with 2099 additions and 8 deletions

View File

@ -59,7 +59,10 @@ func Security() gin.HandlerFunc {
c.Header("X-Content-Type-Options", "nosniff")
c.Header("X-XSS-Protection", "1; mode=block")
c.Header("Referrer-Policy", "strict-origin-when-cross-origin")
c.Header("Content-Security-Policy", "default-src 'self'")
// Set Content Security Policy - more permissive for test pages in development
csp := "default-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'"
c.Header("Content-Security-Policy", csp)
c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
c.Next()

View File

@ -13,6 +13,7 @@ import (
"sync"
"time"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"golang.org/x/time/rate"
@ -167,7 +168,17 @@ func (s *SecurityMiddleware) SecurityHeadersMiddleware(next http.Handler) http.H
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("X-XSS-Protection", "1; mode=block")
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
w.Header().Set("Content-Security-Policy", "default-src 'self'")
// Set Content Security Policy - more permissive for test pages in development
csp := "default-src 'self'"
if !s.config.IsProduction() && strings.HasPrefix(r.URL.Path, "/test/") {
// Allow inline styles and scripts for test pages in development
csp = "default-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'"
s.logger.Debug("Using permissive CSP for test page", zap.String("path", r.URL.Path), zap.String("csp", csp))
} else {
s.logger.Debug("Using default CSP", zap.String("path", r.URL.Path), zap.Bool("is_production", s.config.IsProduction()))
}
w.Header().Set("Content-Security-Policy", csp)
// Add HSTS header for HTTPS
if r.TLS != nil {
@ -178,6 +189,35 @@ func (s *SecurityMiddleware) SecurityHeadersMiddleware(next http.Handler) http.H
})
}
// GinSecurityHeaders returns a Gin-compatible middleware function
func (s *SecurityMiddleware) GinSecurityHeaders() gin.HandlerFunc {
return func(c *gin.Context) {
// Add security headers
c.Header("X-Content-Type-Options", "nosniff")
c.Header("X-Frame-Options", "DENY")
c.Header("X-XSS-Protection", "1; mode=block")
c.Header("Referrer-Policy", "strict-origin-when-cross-origin")
// Set Content Security Policy - more permissive for test pages in development
csp := "default-src 'self'"
if !s.config.IsProduction() && strings.HasPrefix(c.Request.URL.Path, "/test/") {
// Allow inline styles and scripts for test pages in development
csp = "default-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'"
s.logger.Debug("Using permissive CSP for test page", zap.String("path", c.Request.URL.Path), zap.String("csp", csp))
} else {
s.logger.Debug("Using default CSP", zap.String("path", c.Request.URL.Path), zap.Bool("is_production", s.config.IsProduction()))
}
c.Header("Content-Security-Policy", csp)
// Add HSTS header for HTTPS
if c.Request.TLS != nil {
c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
}
c.Next()
}
}
// AuthenticationFailureTracker tracks authentication failures for brute force protection
func (s *SecurityMiddleware) TrackAuthenticationFailure(clientIP, userID string) {
ctx := context.Background()