Secure Coding Guide

Input Validation

// Allowlist validation (preferred over blocklist) func validateEmail(email string) bool { pattern := `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$` matched, _ := regexp.MatchString(pattern, email) return matched && len(email) <= 254 } // Numeric range validation func validateAge(age int) error { if age < 0 || age > 150 { return errors.New("age must be between 0 and 150") } return nil } // File upload validation allowedTypes := map[string]bool{ "image/jpeg": true, "image/png": true, "image/webp": true, } // Always check magic bytes, not just extension or Content-Type

Password Hashing

// Go - bcrypt (recommended) import "golang.org/x/crypto/bcrypt" func hashPassword(password string) (string, error) { bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14) return string(bytes), err } func checkPassword(password, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } // NEVER use: // md5.Sum([]byte(password)) // sha1.New() // sha256.Sum256([]byte(password)) // fast hash, unsuitable for passwords

Secrets Management

// NEVER hardcode secrets // BAD: apiKey := "sk-live-abc123def456..." // GOOD: Environment variables apiKey := os.Getenv("OPENAI_API_KEY") if apiKey == "" { log.Fatal("OPENAI_API_KEY not set") } // BETTER: Secret manager // AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager // .env file (development only, never commit) // Add to .gitignore: // .env // *.pem // *.key // credentials.json

HTTP Security Headers

// Go/Gin middleware func SecurityHeaders() gin.HandlerFunc { return func(c *gin.Context) { 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") c.Header("Permissions-Policy", "geolocation=(), microphone=()") c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains") c.Header("Content-Security-Policy", "default-src 'self'; script-src 'self' 'nonce-{nonce}'; style-src 'self' 'unsafe-inline'") c.Next() } }

CSRF Protection

// Synchronizer Token Pattern // Server generates token, stores in session csrfToken := generateSecureToken(32) // crypto/rand // Include in form // <input type="hidden" name="_csrf" value=""> // Validate on POST if r.FormValue("_csrf") != session.CSRFToken { http.Error(w, "Invalid CSRF token", 403) return } // Double Submit Cookie (for APIs) // Set-Cookie: csrf-token=abc; SameSite=Strict; Secure // X-CSRF-Token: abc (request header must match cookie)

Secure Coding Principles

PrincipleDescription
Defense in depthMultiple security layers; one failure doesn't compromise system
Least privilegeGrant minimum permissions needed for each component
Fail secureOn error, deny access rather than grant
Separation of concernsIsolate auth, data, business logic
Don't trust inputValidate and sanitize all external data
Keep it simpleComplex code has more bugs; simple = more secure