Api Key Exposure in Gin with Bearer Tokens
Api Key Exposure in Gin with Bearer Tokens — how this specific combination creates or exposes the vulnerability
In Gin, a common pattern is to protect routes with an Authorization header using the Bearer token scheme (e.g., Authorization: Bearer
package main
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.Use(func(c *gin.Context) {
auth := c.GetHeader("Authorization")
// Intentionally risky: logging the full Authorization header
fmt.Printf("Auth header: %s\n", auth)
c.Next()
})
r.GET("/profile", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
})
r.Run()
}
If an attacker triggers this endpoint, the token can leak through logs, terminal output, or centralized logging systems. middleBrick’s Data Exposure checks would flag this because tokens in logs constitute sensitive data exposure. Another exposure vector arises when Bearer tokens are passed in query parameters instead of headers, which is common in legacy integrations. For instance:
GET /api/resource?api_key=sk_live_abc123 Host: example.com
In Gin, if the application reads the key via c.Query("api_key") and uses it as a Bearer token or directly as an API key, the key can leak via browser history, server logs, or referrer headers. middleBrick’s Inventory Management and Data Exposure checks identify this risk by correlating spec definitions (e.g., OpenAPI parameters marked as in: query) with runtime behavior, noting that keys in URLs are often stored in access logs. Additionally, if middleware does not enforce secure transport, Bearer tokens may be transmitted over non-TLS connections, violating Encryption checks. Even when using HTTPS, insufficient transport-layer protections or misconfigured TLS can expose tokens to interception. The scanner tests whether responses include strict transport security headers and whether tokens appear in plaintext in any server output, aligning with OWASP API Top 10:2023 Broken Object Level Authorization and Data Exposure risks.
Bearer Tokens-Specific Remediation in Gin — concrete code fixes
To mitigate exposure when using Bearer tokens in Gin, enforce header-only transmission, avoid logging sensitive values, and validate token format server-side. Below are concrete, working examples that address the patterns identified by middleBrick’s checks.
1. Use Authorization header correctly and avoid logging tokens
Instead of logging the entire Authorization header, redact or omit it. Validate the Bearer scheme and extract the token without exposing it in logs:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
r.Use(AuthMiddleware())
r.GET("/profile", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "authenticated"})
})
r.Run()
}
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
auth := c.GetHeader("Authorization")
if auth == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "authorization header required"})
return
}
const bearerPrefix = "Bearer "
if len(auth) < len(bearerPrefix) || auth[:len(bearerPrefix)] != bearerPrefix {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid authorization header format"})
return
}
token := auth[len(bearerPrefix):]
// Perform token validation (e.g., JWT verification, lookup) without logging the token
_ = token // replace with actual validation logic
c.Set("token", token)
c.Next()
}
}
This approach ensures tokens are not logged and that only properly formatted Bearer tokens are accepted, reducing risks flagged under Authentication and Data Exposure checks.
2. Reject tokens in query parameters and enforce HTTPS
Configure Gin to disallow API keys in query strings and enforce TLS. Use middleware to check for suspicious query parameters and reject requests with tokens in the URL:
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Enforce HTTPS in production-like checks; for local dev, you can use a redirect or middleware
r.Use(RequireSecureTransport())
r.Use(NoQueryAPIKey())
r.GET("/api/resource", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"data": "secure"})
})
r.Run()
}
func RequireSecureTransport() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.TLS == nil {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "transport must be secure"})
}
c.Next()
}
}
func NoQueryAPIKey() gin.HandlerFunc {
return func(c *gin.Context) {
if key := c.Query("api_key"); key != "" {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "api_key in query parameters is not allowed"})
return
}
c.Next()
}
}
These measures align with Encryption and Data Exposure checks by ensuring tokens are not transmitted insecurely and are not stored in logs or URLs. For production, combine this with environment-managed secrets and short-lived tokens, and use the middleBrick CLI to validate that these patterns reduce your risk profile.