Comprehensive security implementation for the Modern Go Stack.
Defense-in-depth approach with multiple protection layers:
- Input Sanitization - XSS and SQL injection prevention
- CSRF Protection - Cross-site request forgery prevention with token rotation
- JWT Authentication - Secure token-based authentication with bcrypt password hashing
- Security Headers - Browser security controls and content security policy
- Rate Limiting - DoS and abuse prevention (20 requests/minute per IP)
- Input Validation - Comprehensive request validation with go-playground/validator
- Error Handling - Information disclosure prevention with structured errors
- Request Tracing - Security monitoring with unique request IDs
Custom CSRF middleware in internal/middleware/csrf.go protects all state-changing operations (POST, PUT, PATCH, DELETE).
Configuration:
CSRFConfig{ TokenLength: 32, // 32-byte random tokens TokenLookup: "header:X-CSRF-Token,form:csrf_token", // Multiple token sources CookieName: "_csrf", // Cookie name CookieHTTPOnly: true, // Prevent XSS access CookieSameSite: http.SameSiteStrictMode, // CSRF protection CookieMaxAge: 86400, // 24 hours }Features:
- Token Rotation: New token generated for each request
- Multiple Sources: Supports header and form-based tokens
- Constant-Time Validation: Prevents timing attacks
- Secure Cookies: HTTPOnly and SameSite attributes
- Automatic HTMX Integration: JavaScript automatically includes tokens
Form-based CSRF (Traditional):
<form method="POST" action="/users"> <input type="hidden" name="csrf_token" value="{{.CSRFToken}}" /> <input type="text" name="name" required /> <button type="submit">Create User</button> </form>HTMX with Automatic CSRF:
<!-- CSRF token automatically included by JavaScript --> <button hx-post="/users" hx-vals='{"name": "John Doe"}'> Create User </button>Manual Header-based CSRF:
<button hx-post="/users" hx-headers='{"X-CSRF-Token": "{{.CSRFToken}}"}' hx-vals='{"name": "John Doe"}'> Create User </button>Secure JWT implementation in internal/middleware/auth.go with:
Security Features:
- HMAC-SHA256 signing (configurable signing keys)
- Secure cookie storage with HTTPOnly and SameSite attributes
- Configurable token expiration (24 hours default)
- Password hashing with bcrypt (cost 12)
- Token validation on each request
- Automatic cookie clearing on logout
Configuration:
AuthConfig{ SigningKey: []byte("your-secret-key"), // From JWT_SECRET env var TokenDuration: 24 * time.Hour, // Token expiration RefreshDuration: 7 * 24 * time.Hour, // Refresh token duration Issuer: "go-web-server", // JWT issuer CookieName: "auth_token", // Cookie name CookieSecure: true, // HTTPS only (false in dev) CookieHTTPOnly: true, // Prevent XSS access }Protecting Routes:
// Apply JWT middleware to protected routes protected := e.Group("/api") protected.Use(middleware.JWTMiddleware(authService)) protected.GET("/profile", handlers.Profile)Optional Authentication:
// Optional authentication (doesn't require login) e.Use(middleware.OptionalJWTMiddleware(authService))Getting Current User:
func ProfileHandler(c echo.Context) error { user, exists := middleware.GetCurrentUser(c) if !exists { return c.Redirect(http.StatusFound, "/login") } // Use authenticated user... }Custom sanitization middleware in internal/middleware/sanitize.go:
Features:
- HTML entity escaping
- JavaScript protocol removal
- Event handler removal
- Script tag filtering
- Dangerous pattern detection
Configuration:
SanitizeConfig{ SanitizeHTML: true, // HTML entity escaping SanitizeXSS: true, // XSS pattern removal SanitizeSQL: true, // Basic SQL injection prevention }Automatic Sanitization:
- All form values automatically sanitized
- POST form values cleaned
- Custom sanitization functions supported
Primary Defense - Parameterized Queries:
All database operations use SQLC-generated code with parameterized queries:
-- name: GetUser :one SELECT * FROM users WHERE id = $1 LIMIT 1; -- name: CreateUser :one INSERT INTO users (email, name, bio) VALUES ($1, $2, $3) RETURNING *;Secondary Defense - Input Sanitization:
Additional SQL injection patterns filtered by sanitization middleware:
- SQL comment removal (
--,/*,#) - Dangerous keyword detection (
UNION SELECT,DROP TABLE, etc.) - Quote escaping as fallback
Comprehensive security headers in main.go and internal/middleware/errors.go:
Echo Security Middleware:
echomiddleware.SecureWithConfig(echomiddleware.SecureConfig{ XSSProtection: "1; mode=block", ContentTypeNosniff: "nosniff", XFrameOptions: "DENY", HSTSMaxAge: 31536000, // 1 year ContentSecurityPolicy: "default-src 'self'; ...", })Custom Security Headers:
// Additional security headers c.Response().Header().Set("Referrer-Policy", "strict-origin-when-cross-origin") c.Response().Header().Set("Permissions-Policy", "geolocation=(), microphone=(), camera=()") c.Response().Header().Set("Cross-Origin-Opener-Policy", "same-origin") c.Response().Header().Set("Cross-Origin-Embedder-Policy", "require-corp")Restrictive CSP policy balancing security and functionality:
default-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://fonts.gstatic.com; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:; connect-src 'self'; font-src 'self' https://fonts.googleapis.com https://fonts.gstatic.com; Policy Rationale:
'unsafe-inline'for styles: Required for Pico.css and dynamic theme switching'unsafe-eval'for scripts: Required for HTMX functionality- External fonts: Google Fonts for typography
- Data URIs: For inline images/icons
IP-based rate limiting with configurable limits:
Configuration:
echomiddleware.RateLimiterWithConfig(echomiddleware.RateLimiterConfig{ Store: echomiddleware.NewRateLimiterMemoryStore(20), // 20 req/min IdentifierExtractor: func(c echo.Context) (string, error) { return c.RealIP(), nil // Rate limit by client IP }, ErrorHandler: func(_ echo.Context, err error) error { return middleware.ErrTooManyRequests.WithInternal(err) }, })Features:
- Memory-based storage (suitable for single instance)
- Real IP detection (works behind proxies)
- Configurable limits per endpoint
- Graceful error handling
- Prometheus metrics integration
Using go-playground/validator with custom rules:
Built-in Validations:
- Email format validation
- Password strength requirements
- String length limits
- Required field validation
- URL format validation
Custom Password Validation:
// Password must be 8+ chars with uppercase, lowercase, and numbers func passwordValidator(fl validator.FieldLevel) bool { password := fl.Field().String() return len(password) >= 8 && strings.ContainsAny(password, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") && strings.ContainsAny(password, "abcdefghijklmnopqrstuvwxyz") && strings.ContainsAny(password, "0123456789") }Usage Example:
type RegisterRequest struct { Email string `json:"email" validate:"required,email"` Name string `json:"name" validate:"required,min=2,max=100"` Password string `json:"password" validate:"required,password"` ConfirmPassword string `json:"confirm_password" validate:"required"` }Comprehensive error handling in internal/middleware/errors.go:
Error Categories:
- Validation errors (400)
- Authentication errors (401)
- Authorization errors (403)
- Not found errors (404)
- Rate limit errors (429)
- Internal server errors (500)
Production Safety:
- Internal error details never exposed to clients
- Generic error messages in production
- Detailed logging for debugging
- Request correlation IDs for tracing
Error Response Format:
{ "type": "validation", "error": "Bad Request", "message": "Validation failed", "details": [ {"field": "email", "message": "invalid email format"} ], "code": 400, "request_id": "req-123456", "timestamp": "1640995200" }Prometheus metrics for security monitoring:
// CSRF protection metrics csrfTokensGenerated // Total tokens generated csrfValidationFailures // Failed CSRF validations // Authentication metrics userLoginAttempts // Total login attempts userLoginFailures // Failed login attempts userRegistrations // New user registrations // Request security metrics requestsBlocked // Requests blocked by rate limiting validationFailures // Input validation failuresStructured logging for security events:
slog.Warn("Failed login attempt", "email", email, "remote_ip", c.RealIP(), "user_agent", c.Request().UserAgent(), "request_id", requestID)- All forms include CSRF tokens
- Passwords hashed with bcrypt
- Input validation on all endpoints
- SQL queries use parameters (SQLC)
- Error messages don't leak information
- Security headers configured
- Rate limiting active
- HTTPS enabled (TLS certificates)
- Secure JWT signing keys
- Database access restricted
- Security headers verified
- Rate limits appropriate for traffic
- Monitoring and alerting configured
- Log retention policies set
- Regular security updates applied
-
JWT Management:
- Use strong, random signing keys (256+ bits)
- Rotate signing keys regularly
- Set appropriate token expiration times
- Store tokens in HTTPOnly cookies
-
Password Security:
- Enforce strong password requirements
- Use bcrypt with appropriate cost (12+)
- Implement account lockout after failed attempts
- Consider 2FA for sensitive applications
-
Database Security:
- Use parameterized queries exclusively
- Implement connection pooling limits
- Regular security updates for PostgreSQL
- Database access limited to application user
-
Monitoring:
- Monitor failed authentication attempts
- Alert on unusual traffic patterns
- Log security events with correlation IDs
- Regular security audit reviews
This security implementation provides enterprise-grade protection while maintaining usability and performance.