Skip to content

Security: dunamismax/go-web-server

Security

docs/security.md

Security Guide

Comprehensive security implementation for the Modern Go Stack.

Security Architecture

Defense-in-depth approach with multiple protection layers:

  1. Input Sanitization - XSS and SQL injection prevention
  2. CSRF Protection - Cross-site request forgery prevention with token rotation
  3. JWT Authentication - Secure token-based authentication with bcrypt password hashing
  4. Security Headers - Browser security controls and content security policy
  5. Rate Limiting - DoS and abuse prevention (20 requests/minute per IP)
  6. Input Validation - Comprehensive request validation with go-playground/validator
  7. Error Handling - Information disclosure prevention with structured errors
  8. Request Tracing - Security monitoring with unique request IDs

CSRF Protection

Implementation

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

Usage Examples

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>

JWT Authentication

Implementation

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 }

Usage Examples

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... }

Input Sanitization

XSS Prevention

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

SQL Injection Prevention

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

Security Headers

Implementation

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")

Content Security Policy

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

Rate Limiting

Implementation

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

Input Validation

Comprehensive Validation

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"` }

Error Handling & Information Disclosure Prevention

Structured Error Responses

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" }

Monitoring & Alerting

Security Metrics

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 failures

Security Event Logging

Structured logging for security events:

slog.Warn("Failed login attempt", "email", email, "remote_ip", c.RealIP(), "user_agent", c.Request().UserAgent(), "request_id", requestID)

Security Checklist

Development

  • 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

Production

  • 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

Security Best Practices

  1. JWT Management:

    • Use strong, random signing keys (256+ bits)
    • Rotate signing keys regularly
    • Set appropriate token expiration times
    • Store tokens in HTTPOnly cookies
  2. Password Security:

    • Enforce strong password requirements
    • Use bcrypt with appropriate cost (12+)
    • Implement account lockout after failed attempts
    • Consider 2FA for sensitive applications
  3. Database Security:

    • Use parameterized queries exclusively
    • Implement connection pooling limits
    • Regular security updates for PostgreSQL
    • Database access limited to application user
  4. 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.

There aren’t any published security advisories