Clickjacking in Gin with Bearer Tokens
Clickjacking in Gin with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Clickjacking is a client-side UI redressing attack where an invisible or disguised element (e.g., a button or link) is placed over a legitimate action, causing a user to inadvertently perform an unwanted operation. In a Gin-based API that relies on Bearer Tokens for authentication, clickjacking can expose privileged actions even when tokens are transmitted securely over HTTPS. The risk arises when protected endpoints render HTML or are embedded inside frames if the server does not enforce frame-busting or Content Security Policy (CSP) directives. For example, an authenticated UI served by Gin might include an endpoint like /confirm-payment that accepts a Bearer Token in the Authorization header. If this UI is loaded inside an attacker-controlled iframe, a malicious site can overlay a transparent element on top of a "Confirm" button, tricking the user into submitting a transaction without their knowledge. Because the request includes the Bearer Token automatically via browser context (cookies or JavaScript authorization headers), the server processes the action as legitimate. Even if the API expects the Bearer Token in headers, browser-based clients that attach the token via Authorization headers in JavaScript are still susceptible when the page is framed. The vulnerability is compounded when the Gin server does not validate the Origin or Referer headers, or when CORS is misconfigured to allow cross-origin requests from attacker domains. This creates a scenario where token-based authentication does not protect against unauthorized UI interactions. MiddleBrick’s scans detect missing anti-clickjacking controls by analyzing response headers and CSP configurations across the 12 security checks, highlighting whether frame-embedding risks exist for authenticated flows.
Bearer Tokens-Specific Remediation in Gin — concrete code fixes
To mitigate clickjacking in Gin when using Bearer Tokens, implement frame-protection headers and ensure token handling does not rely solely on implicit browser behavior. Below are concrete code examples demonstrating secure configurations.
1. Set X-Frame-Options Header
Prevent your endpoints from being embedded in frames by adding the X-Frame-Options header. In Gin, this can be applied globally or per route.
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// Global middleware to set X-Frame-Options for all responses
r.Use(func(c *gin.Context) {
c.Writer.Header().Set("X-Frame-Options", "DENY")
c.Next()
})
r.GET("/dashboard", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "secure page"})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
2. Configure Content Security Policy (CSP)
CSP provides finer control by restricting which origins can embed your content. Use the Content-Security-Policy header to block framing entirely or limit it to trusted sources.
c.Use(func(c *gin.Context) {
c.Writer.Header().Set("Content-Security-Policy", "frame-ancestors 'none'; frame-src 'none'")
c.Next()
})
3. Secure Bearer Token Usage in Requests
Ensure that clients send Bearer Tokens via the Authorization header and avoid storing tokens in ways that make them accessible to framed contexts. This example shows a Gin route that validates the token before proceeding.
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "authorization header required"})
return
}
// Expected format: Bearer <token>
const bearerPrefix = "Bearer "
if len(authHeader) < len(bearerPrefix) || authHeader[:len(bearerPrefix)] != bearerPrefix {
c.AbortWithStatusJSON(401, gin.H{"error": "invalid authorization header format"})
return
}
token := authHeader[len(bearerPrefix):]
// Validate token (e.g., JWT verification)
if !isValidToken(token) {
c.AbortWithStatusJSON(403, gin.H{"error": "invalid token"})
return
}
c.Next()
}
}
func isValidToken(token string) bool {
// Placeholder for actual validation logic
return token == "valid_token_123"
}
func main() {
r := gin.Default()
r.Use(AuthMiddleware())
r.GET("/transfer", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "action executed securely"})
})
r.Run()
}
4. Avoid Token Leakage in Browser Contexts
Do not include Bearer Tokens in URLs or local storage where they can be accessed via JavaScript in a framed page. Instead, rely on HttpOnly cookies for session management when serving UI, or ensure that APIs requiring tokens are not embedded in vulnerable frames. MiddleBrick’s scans flag endpoints that expose tokens in client-side contexts or lack appropriate CSP framing rules.