Go (Golang) Tutorial 0/45 lessons ~6 min read Lesson 43

    Security Best Practices

    Go backend security spans input validation, SQL injection prevention, authentication (JWT, OAuth2), HTTPS/TLS, secrets management, and dependency scanning.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Go backend security spans input validation, SQL injection prevention, authentication (JWT, OAuth2), HTTPS/TLS, secrets management, and dependency scanning. Go's memory safety prevents buffer overflows, but application-level vulnerabilities remain your responsibility.

    OWASP Top 10 applies: broken access control, injection, insecure design. Use golang.org/x/crypto/bcrypt for passwords, crypto/rand for tokens, and run govulncheck in CI. Interviewers ask JWT validation, CORS, rate limiting, and secret storage.

    This lesson covers JWT middleware, parameterized queries, security headers, and dependency vulnerability scanning — production security checklist for Go APIs.

    The story

    A fintech API gateway validates JWT signatures with pinned public keys, enforces TLS 1.3 for all outbound calls to payment processors, and sanitizes SQL parameters through prepared statements — never string concatenation. When Cloudflare mitigates a DDoS, the origin Go service must still reject forged internal headers and rate-limit authenticated abuse.

    Security in Go layers defense: crypto/rand for tokens, bcrypt for passwords, middleware for auth, and regular govulncheck scans in CI for known CVEs in dependencies.

    Understanding the topic

    Key concepts

    • Parameterized SQL — never string concat user input.
    • bcrypt.HashPassword for storage; constant-time compare.
    • JWT: validate signature, exp, iss; don't trust claims without verify.
    • crypto/rand for tokens — never math/rand for secrets.
    • HTTPS only in production; HSTS header.
    • govulncheck scans module vulnerabilities.

    Step-by-step explanation

    1. Middleware validates JWT on protected routes.
    2. RBAC checks role claim against required permission.
    3. Rate limiter per IP prevents brute force.
    4. Input validation on all external data.
    5. Secrets from env/vault — rotated regularly.
    6. CI runs govulncheck and docker scan on every build.

    Practical code example

    Security middleware with headers, body limit, and JWT auth stub:

    go
    package main
    import (
    "context"
    "net/http"
    "strings"
    )
    type ctxKey string
    const userIDKey ctxKey = "userID"
    func securityHeaders(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("X-Content-Type-Options", "nosniff")
    w.Header().Set("X-Frame-Options", "DENY")
    w.Header().Set("Strict-Transport-Security", "max-age=31536000")
    next.ServeHTTP(w, r)
    })
    }
    func maxBody(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1MB
    next.ServeHTTP(w, r)
    })
    }
    func jwtAuth(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    auth := r.Header.Get("Authorization")
    if !strings.HasPrefix(auth, "Bearer ") {
    http.Error(w, "unauthorized", http.StatusUnauthorized)
    return
    }
    token := strings.TrimPrefix(auth, "Bearer ")
    // validateJWT(token) — verify signature, exp, issuer
    if token == "" {
    http.Error(w, "invalid token", http.StatusUnauthorized)
    return
    }
    ctx := context.WithValue(r.Context(), userIDKey, "user-123")
    next.ServeHTTP(w, r.WithContext(ctx))
    })
    }
    func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("GET /api/profile", func(w http.ResponseWriter, r *http.Request) {
    uid := r.Context().Value(userIDKey)
    w.Write([]byte("profile:" + uid.(string)))
    })
    handler := securityHeaders(maxBody(jwtAuth(mux)))
    http.ListenAndServe(":8080", handler)
    }

    Line-by-line code explanation

    • crypto/rand.Read(b) generates cryptographically secure random bytes for tokens.
    • bcrypt.GenerateFromPassword hashes passwords with adaptive cost — never store plaintext.
    • db.QueryContext(ctx, "SELECT ... WHERE id=$1", id) — parameterized queries prevent SQL injection.
    • html.EscapeString(s) prevents XSS when reflecting user input in HTML responses.
    • tls.Config{MinVersion: tls.VersionTLS12} enforces modern TLS on server and client.
    • middleware auth validates Bearer tokens before reaching business handlers.
    • govulncheck ./... reports known vulnerabilities in module dependencies.
    • limit request body sizehttp.MaxBytesReader prevents large payload DoS.

    Key takeaway: Use golang-jwt/jwt for real validation. MaxBytesReader prevents large body DoS. Never log JWT or secrets.

    Real-world use

    Where you'll use this in production

    • OAuth2 login flows with Google/GitHub providers.
    • API key authentication for developer portals.
    • PCI-compliant payment APIs with audit logging.
    • Zero-trust internal service mTLS on service mesh.

    Best practices

    • Validate all input; whitelist acceptable values.
    • Use bcrypt/scrypt for passwords; never store plaintext.
    • Short-lived JWT with refresh token rotation.
    • Run govulncheck and dependabot in CI.
    • Principle of least privilege for DB and cloud IAM.
    • Security headers on all HTTP responses.

    Common mistakes

    • SQL string concatenation with user input.
    • JWT alg:none attack — whitelist allowed algorithms.
    • Secrets in git history or Docker layers.
    • CORS * with credentials enabled.
    • Logging Authorization headers.

    Advanced interview questions

    Q1BeginnerPrevent SQL injection in Go?
    Parameterized queries with $1/? placeholders — never fmt.Sprintf SQL.
    Q2BeginnerSecure random tokens?
    crypto/rand.Read — not math/rand.
    Q3IntermediateJWT validation checklist?
    Verify signature, exp not passed, iss/aud match, use HTTPS transmission.
    Q4Intermediategovulncheck purpose?
    Scans dependencies against Go vulnerability database.
    Q5AdvancedSecure public REST API design.
    HTTPS, JWT/OAuth, rate limit, input validation, WAF, audit log, no verbose errors, dependency scanning.

    Summary

    Parameterized SQL, bcrypt passwords, crypto/rand tokens. Validate JWT properly; security headers on all responses. Secrets in vault/env — never in source or images. govulncheck in CI for dependency vulnerabilities. Next lesson: deployment basics.

    Ready to mark this lesson complete?Track your journey across the entire course.