Edge Security: Zero-Allocation CORS Middleware in FastHTTP
How LZStock implements a high-performance, O(1) lookup CORS middleware at the API Gateway to enforce strict Same-Origin Policies without sacrificing latency.
- Kill the Preflight Penalty: Aggressively cached
OPTIONSrequests usingMax-Age: 86400and short-circuited them at the Edge, preventing duplicate routing and saving internal CPU cycles. - Origin Verification: Bypassed slow array iterations by implementing a Hash Map for strict, zero-latency origin validation in production environments.
- Solve the Credentials Paradox: Dynamically echoed validated origins instead of relying on the forbidden
*wildcard, ensuring strict browser compliance whenAllow-Credentialsis true.
1. The Objective
Browsers natively enforce the Same-Origin Policy (SOP), blocking malicious websites from executing JavaScript that steals data from our APIs. CORS is the controlled mechanism to punch a secure hole through this wall for trusted frontend domains.
However, CORS introduces a massive performance risk: The Preflight Penalty. For complex requests, browsers send an OPTIONS request before the actual POST/PUT request. If the API Gateway processes this inefficiently, every frontend API call suffers a 2x latency penalty. The objective is to build a highly optimized middleware that authorizes origins in time and aggressively caches preflight approvals.
2. The Mental Model & Preflight Caching
The architecture ensures that the expensive preflight request is handled strictly at the Edge (Gateway) and cached by the browser for 24 hours, shielding the internal microservices from OPTIONS traffic.
Codebase Anatomy
mods/bc15-api-gateway
└── server
└── middle
└── cors.go
Core Implementation
Below is the curated FastHTTP middleware. Notice how we utilize a Hash Map for origin lookups and explicitly intercept OPTIONS requests before they reach the routing layer.
// mods/bc15-api-gateway/server/middle/cors.go
func CORS(env string) routing.Handler {
return func(ctx *routing.Context) error {
origin := string(ctx.Request.Header.Peek("Origin"))
// 1. Development Mode: Bypass security for local testing
if env == "development" {
ctx.Response.Header.Set("Access-Control-Allow-Origin", "*")
ctx.Response.Header.Set("Access-Control-Allow-Headers", "*")
ctx.Response.Header.Set("Access-Control-Allow-Methods", "*")
} else {
// 2. Production Mode: Strict O(1) Origin Verification
if _, allowed := allowedOriginsMap[origin]; allowed {
// Must echo back the exact origin when credentials are true
ctx.Response.Header.Set("Access-Control-Allow-Origin", origin)
} else if origin != "" {
log.Printf("[SECURITY] Rejected CORS origin attempt: %s", origin)
// We do not abort here; we simply omit the Allow-Origin header,
// letting the browser block the response on the client side.
}
// 3. Strict Security Policies
ctx.Response.Header.Set("Access-Control-Allow-Credentials", "true")
ctx.Response.Header.Set("Access-Control-Allow-Headers", "Accept, Authorization, Content-Type, Origin, X-Requested-With")
ctx.Response.Header.Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
}
// 4. Preflight Caching: Tell the browser to cache this approval for 24 hours (86400 seconds)
ctx.Response.Header.Set("Access-Control-Max-Age", "86400")
// 5. Short-Circuit Preflight Requests
if ctx.IsOptions() {
ctx.SetStatusCode(fasthttp.StatusOK)
ctx.Abort() // Stop the middleware chain, return immediately
return nil
}
// Proceed to the next middleware/handler
ctx.Next()
return nil
}
}
Edge Cases & Trade-offs
- The Allow-Credentials: true Paradox: If your frontend needs to send HTTP Cookies or Authorization Headers, you must set Access-Control-Allow-Credentials to true. However, the browser CORS specification strictly forbids setting Allow-Origin: * when credentials are true. This forces our backend to dynamically read the incoming Origin header, validate it against our Map, and echo it back specifically.
- Silent Rejections: Notice that if an origin is invalid, we log it but do not return a 403 Forbidden immediately. Instead, we simply omit the Allow-Origin header and let the request proceed. Why? Because CORS is a browser security feature, not a server security feature. A malicious script outside a browser (like curl or Postman) ignores CORS entirely. We rely on our Authentication middleware down the chain to actually block unauthorized server access.
The Outcome
By converting array lookups to Hash Maps and aggressively setting Max-Age headers, the API Gateway enforces strict browser boundaries without adding measurable CPU overhead or unnecessary network round-trips to the frontend latency budget.