91 lines
2.7 KiB
Go
91 lines
2.7 KiB
Go
package middleware
|
|
|
|
import (
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// SecurityConfig holds configuration for security headers middleware
|
|
type SecurityConfig struct {
|
|
// EnableHSTS enables HTTP Strict Transport Security header
|
|
EnableHSTS bool
|
|
// HSTSMaxAge is the max-age value for HSTS in seconds (default: 31536000 = 1 year)
|
|
HSTSMaxAge int
|
|
// EnableNoSniff enables X-Content-Type-Options: nosniff
|
|
EnableNoSniff bool
|
|
// EnableXSSFilter enables X-XSS-Protection header
|
|
EnableXSSFilter bool
|
|
// EnableFrameDeny enables X-Frame-Options: DENY
|
|
EnableFrameDeny bool
|
|
// ContentSecurityPolicy sets the Content-Security-Policy header
|
|
ContentSecurityPolicy string
|
|
// ReferrerPolicy sets the Referrer-Policy header
|
|
ReferrerPolicy string
|
|
}
|
|
|
|
// DefaultSecurityConfig returns a secure default configuration
|
|
func DefaultSecurityConfig() SecurityConfig {
|
|
return SecurityConfig{
|
|
EnableHSTS: true,
|
|
HSTSMaxAge: 31536000, // 1 year
|
|
EnableNoSniff: true,
|
|
EnableXSSFilter: true,
|
|
EnableFrameDeny: true,
|
|
ContentSecurityPolicy: "default-src 'self'",
|
|
ReferrerPolicy: "strict-origin-when-cross-origin",
|
|
}
|
|
}
|
|
|
|
// SecurityHeaders creates a middleware that adds security headers to responses
|
|
func SecurityHeaders(config SecurityConfig) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
// Prevent MIME type sniffing
|
|
if config.EnableNoSniff {
|
|
c.Header("X-Content-Type-Options", "nosniff")
|
|
}
|
|
|
|
// XSS protection (legacy, but still useful for older browsers)
|
|
if config.EnableXSSFilter {
|
|
c.Header("X-XSS-Protection", "1; mode=block")
|
|
}
|
|
|
|
// Prevent clickjacking
|
|
if config.EnableFrameDeny {
|
|
c.Header("X-Frame-Options", "DENY")
|
|
}
|
|
|
|
// HTTP Strict Transport Security
|
|
if config.EnableHSTS {
|
|
hstsValue := "max-age=31536000; includeSubDomains"
|
|
if config.HSTSMaxAge > 0 {
|
|
hstsValue = "max-age=" + string(rune(config.HSTSMaxAge)) + "; includeSubDomains"
|
|
}
|
|
c.Header("Strict-Transport-Security", hstsValue)
|
|
}
|
|
|
|
// Content Security Policy
|
|
if config.ContentSecurityPolicy != "" {
|
|
c.Header("Content-Security-Policy", config.ContentSecurityPolicy)
|
|
}
|
|
|
|
// Referrer Policy
|
|
if config.ReferrerPolicy != "" {
|
|
c.Header("Referrer-Policy", config.ReferrerPolicy)
|
|
}
|
|
|
|
// Permissions Policy (formerly Feature-Policy)
|
|
c.Header("Permissions-Policy", "geolocation=(), microphone=(), camera=()")
|
|
|
|
// Cache control for API responses
|
|
c.Header("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate")
|
|
c.Header("Pragma", "no-cache")
|
|
c.Header("Expires", "0")
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
// SecureHeaders is a convenience function that applies default security headers
|
|
func SecureHeaders() gin.HandlerFunc {
|
|
return SecurityHeaders(DefaultSecurityConfig())
|
|
}
|