APIs are a core part of modern software, but they are also vulnerable to attacks. Here’s how to secure your APIs using Go (Golang) with practical examples.


1. Enforce HTTPS

Always use HTTPS to encrypt data in transit.

  • Example:
    Use http.ListenAndServeTLS to enforce HTTPS in Go:
  package main

  import (
      "log"
      "net/http"
  )

  func main() {
      http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
          w.Write([]byte("Hello, HTTPS!"))
      })

      log.Fatal(http.ListenAndServeTLS(":443", "server.crt", "server.key", nil))
  }

2. Use Strong Authentication and Authorization

Ensure only authorized users and systems can access your APIs.

  • Example:
    Validate JWT tokens in Go using the github.com/golang-jwt/jwt library:
  package main

  import (
      "fmt"
      "net/http"
      "github.com/golang-jwt/jwt/v5"
  )

  var secretKey = []byte("your-secret-key")

  func validateToken(next http.Handler) http.Handler {
      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          tokenString := r.Header.Get("Authorization")
          token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
              return secretKey, nil
          })
          if err != nil || !token.Valid {
              http.Error(w, "Unauthorized", http.StatusUnauthorized)
              return
          }
          next.ServeHTTP(w, r)
      })
  }

  func main() {
      http.Handle("/", validateToken(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          w.Write([]byte("Authenticated"))
      })))
      http.ListenAndServe(":8080", nil)
  }

3. Validate Input Data

Sanitize and validate inputs to prevent injection attacks.

  • Example:
    Use Go’s validator package for validation:
  package main

  import (
      "encoding/json"
      "net/http"
      "github.com/go-playground/validator/v10"
  )

  type User struct {
      Email string `json:"email" validate:"required,email"`
  }

  var validate = validator.New()

  func main() {
      http.HandleFunc("/api/user", func(w http.ResponseWriter, r *http.Request) {
          var user User
          json.NewDecoder(r.Body).Decode(&user)

          err := validate.Struct(user)
          if err != nil {
              http.Error(w, "Invalid input", http.StatusBadRequest)
              return
          }
          w.Write([]byte("Valid input"))
      })
      http.ListenAndServe(":8080", nil)
  }

4. Rate Limit and Throttle Requests

Prevent abuse by limiting API calls.

  • Example:
    Use golang.org/x/time/rate for rate limiting:
  package main

  import (
      "net/http"
      "golang.org/x/time/rate"
  )

  var limiter = rate.NewLimiter(1, 3) // 1 request per second with a burst of 3

  func rateLimitMiddleware(next http.Handler) http.Handler {
      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          if !limiter.Allow() {
              http.Error(w, "Rate limit exceeded", http.StatusTooManyRequests)
              return
          }
          next.ServeHTTP(w, r)
      })
  }

  func main() {
      http.Handle("/", rateLimitMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          w.Write([]byte("Welcome"))
      })))
      http.ListenAndServe(":8080", nil)
  }

5. Monitor and Log API Activity

Log requests and responses for debugging and suspicious activity.

  • Example:
    Use Go’s log package to log activity:
  package main

  import (
      "log"
      "net/http"
  )

  func loggingMiddleware(next http.Handler) http.Handler {
      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          log.Printf("%s %s %s", r.Method, r.URL.Path, r.RemoteAddr)
          next.ServeHTTP(w, r)
      })
  }

  func main() {
      http.Handle("/", loggingMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          w.Write([]byte("Logged"))
      })))
      http.ListenAndServe(":8080", nil)
  }

6. Use Secure API Gateways

Integrate your API with secure gateways for centralized security and monitoring.

  • Example:
    Use NGINX or AWS API Gateway for security, applying rate limits and authentication layers.

7. Avoid Exposing Sensitive Data

Ensure sensitive data is not exposed in logs or API responses.

  • Example:
    Mask sensitive data in JSON responses:
  package main

  import (
      "encoding/json"
      "net/http"
  )

  type User struct {
      ID       int    `json:"id"`
      Name     string `json:"name"`
      Password string `json:"-"` // Exclude from JSON
  }

  func main() {
      http.HandleFunc("/api/user", func(w http.ResponseWriter, r *http.Request) {
          user := User{ID: 1, Name: "John Doe", Password: "secret123"}
          json.NewEncoder(w).Encode(user)
      })
      http.ListenAndServe(":8080", nil)
  }

8. Implement CORS Policies

Control cross-origin requests to your API.

  • Example:
    Use Go’s github.com/rs/cors package:
  package main

  import (
      "net/http"
      "github.com/rs/cors"
  )

  func main() {
      c := cors.New(cors.Options{
          AllowedOrigins:   []string{"https://trusted.com"},
          AllowCredentials: true,
      })

      handler := c.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          w.Write([]byte("CORS Enabled"))
      }))
      http.ListenAndServe(":8080", handler)
  }

9. Secure API Endpoints

Restrict sensitive routes to authorized users.

  • Example:
    Add middleware to check user roles:
  package main

  import (
      "net/http"
  )

  func adminMiddleware(next http.Handler) http.Handler {
      return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          if r.Header.Get("X-Role") != "admin" {
              http.Error(w, "Forbidden", http.StatusForbidden)
              return
          }
          next.ServeHTTP(w, r)
      })
  }

  func main() {
      http.Handle("/admin", adminMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
          w.Write([]byte("Admin Access"))
      })))
      http.ListenAndServe(":8080", nil)
  }

10. Scan for Vulnerabilities

Run security scans regularly to find and fix vulnerabilities.

  • Example:
    Use tools like OWASP ZAP or Gosec:
  go install github.com/securego/gosec/v2/cmd/gosec@latest
  gosec ./...

11. Protect Against DDoS Attacks

Mitigate DDoS attacks using rate limiting and IP whitelisting.

  • Example:
    Use Cloudflare to set up DDoS protection for your API endpoint.

12. Keep APIs Updated

Regularly update your dependencies and Go runtime.

  • Example:
    Use go get -u to update dependencies:
  go get -u all

Conclusion

Securing APIs in Go involves a mix of best practices and practical implementation. Use these examples to start protecting your APIs effectively.