Security Best Practices Summary
OWASP-oriented checklist for Go HTTP and gRPC APIs.
Apply these rules in service templates, code review, and CI so every Go API fails closed and ships with measurable supply-chain hygiene.
How to Use This List
- Tick items as your org's Go service template adopts them.
- Encode Tier A controls in CI (govulncheck, lint, integration tests for auth).
- Map Tier B items to OWASP API Security Top 10 categories in your risk register.
- Revisit when exposing new public routes, adding browser clients, or onboarding gRPC services.
A - Transport and server hardening
- Set
ReadHeaderTimeouton every productionhttp.Server. Blocks slow header attacks before handlers execute. - Configure
ReadTimeout,WriteTimeout, andIdleTimeoutper SLO. Prevents hung connections and descriptor leaks. - Set
tls.Config.MinVersionto TLS 1.2 or higher on TLS listeners. Documents acceptable protocol floor for audits. - Serve complete certificate chains and monitor
NotAfterdates. Incomplete chains cause client failures; expiry causes outages. - Use mTLS or mesh identity for service-to-service calls when the threat model requires it. Network location is not authentication.
- Never set
InsecureSkipVerifyon production outbound clients. Disables certificate and hostname verification. - Inject configured
http.Clientinstances with timeouts; neverhttp.DefaultClientin handlers. Default client has no deadline.
B - Authentication and authorization
- Authenticate in middleware before business handlers; fail closed on missing credentials. Returns 401, never anonymous fallback on protected routes.
- Return 403 when authenticated users lack permission; reserve 401 for auth failures. Clear semantics aid clients and monitoring.
- Pin JWT algorithms in validation; reject unexpected
algvalues. Prevents algorithm confusion attacks. - Use short-lived access tokens and a documented rotation or revocation strategy. Limits stolen token blast radius.
- Check resource-level authorization, not only global roles. Prevents IDOR even when
role: useris present. - Protect
/metrics,/debug, and admin routes with the same auth rigor as APIs. Attackers scan defaults. - Store context principals with unexported key types. Avoids string-key collisions across middleware packages.
C - Input, output, and data
- Cap request bodies with
http.MaxBytesReaderbefore decode. Rejects oversized payloads early. - Validate JSON with typed DTOs plus semantic rules after syntax parse. Valid JSON can still be dangerous.
- Use
DisallowUnknownFieldson strict public APIs when appropriate. Surfaces client bugs and probing. - Parameterize all SQL; never format queries with user input. Stops SQL injection at the source.
- Render HTML with
html/template, nottext/template. Auto-escapes content in HTML context. - Return generic error messages to clients; log details server-side with request IDs. Prevents information leakage.
- Avoid mass assignment: separate public input structs from persistence models. Blocks privilege escalation via JSON fields.
D - Browser and edge controls
- Set session cookies
HttpOnly,Secure, and appropriateSameSite. Reduces XSS exfiltration and cross-site cookie abuse. - Require CSRF tokens on cookie-authenticated mutating requests. Browsers send cookies automatically; CORS does not stop CSRF.
- Allowlist CORS origins; never reflect arbitrary
Originvalues. Open CORS plus cookies enables data theft. - Apply security headers (CSP, HSTS,
X-Content-Type-Options, frame ancestors) on all responses including errors. Headers must not depend on success paths only. - Rate limit login and expensive endpoints more aggressively than health checks. Slows credential stuffing and abuse.
- Trust
X-Forwarded-Foronly from known load balancers. Prevents client IP spoofing for rate limits and audit logs.
E - Secrets and configuration
- Load secrets from environment or secret managers; never commit credentials. Fail process start when required secrets are missing.
- Compare API keys and HMACs with
crypto/subtle.ConstantTimeCompare. Reduces timing side channels. - Hash passwords with bcrypt or argon2 via
golang.org/x/crypto. Never store or compare plaintext passwords. - Redact tokens and PII from structured logs. Logs become a secondary breach channel.
- Separate dev and prod keys; rotate on employee departure and incidents. Limits blast radius of leaked config.
F - Supply chain and operations
- Run
govulncheck ./...in CI and fail on actionable reachable findings. Catches known CVEs in your import graph. - Commit
go.sumand rungo mod verifyin CI. Detects module tampering at download. - Generate and store SBOM per release artifact. Speeds incident response and audit evidence.
- Pin Go toolchain version in CI images matching
go.mod. Security patches land in Go patch releases. - Review
replacedirectives and private forks as first-party code. Bypass normal module provenance checks. - Document exception allowlists for vuln findings with owners and expiry. Prevents permanent "temporary" waivers.
FAQs
Which tier should block a production deploy?
Tier A transport and auth failures, reachable govulncheck findings without approved exceptions, and missing secrets at startup should block deploy.
Tier B browser controls may phase in per client type.
How does this map to OWASP API Top 10?
Broken auth maps to section B; unsafe input to C; SSRF and excessive data exposure to C and handler design; misconfiguration to A and D; inventory and logging to F and observability practices.
Do gRPC services use the same checklist?
Yes, with TLS credentials and interceptors replacing HTTP middleware for auth, limits, and metadata validation.
What is the minimum viable Go API security template?
Dedicated mux, server timeouts, TLS min version, auth middleware, body limits, parameterized SQL, govulncheck in CI, and configured outbound clients.
Should internal microservices skip rate limits?
Apply lighter limits or per-service quotas still.
Compromised workloads inside the mesh generate abusive east-west traffic too.
How do I track checklist adoption?
Encode items in arch unit tests, custom golangci-lint wrappers, and deployment checklists tied to service catalog metadata.
Are security headers needed for JSON-only APIs?
Yes - minimal CSP and nosniff still help when responses are misinterpreted by browsers or proxies.
When is CSRF not required?
When browsers never send session cookies and clients use Bearer tokens not accessible to attacker-controlled sites.
XSS defense remains critical.
How often should we regenerate SBOMs?
Every release build.
Attach the SBOM to the container image OCI artifact or release page.
What about third-party Go frameworks like gin or chi?
Framework routers do not remove checklist items.
Verify their middleware ordering preserves auth, limits, and security headers as intended.
Related
- Security for Go Services: Defaults and Gaps - conceptual security model
- Go Security Basics - runnable starting snippets
- Authentication & Authorization Patterns - auth middleware patterns
- Dependency Scanning with govulncheck & SBOM - CI scanning detail
- crypto/tls Configuration & Certificate Management - TLS and mTLS depth
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify at build).