HIGH dns rebindingginapi keys

Dns Rebinding in Gin with Api Keys

Dns Rebinding in Gin with Api Keys — how this specific combination creates or exposes the vulnerability

DNS rebinding is an attacker-controlled DNS response that causes a victim’s browser to gradually switch the IP address for a hostname from a public address to a private address, such as 127.0.0.1. In a Gin-based service that uses API keys for authorization, this creates a situation where a trusted origin (e.g., your domain) can be manipulated into making requests to internal endpoints that would otherwise be unreachable. Because Gin relies on standard HTTP middleware for routing and authentication, if API key validation is applied only at the handler or route level without network-layer enforcement, a rebinding attack can bypass intended access boundaries.

Consider a Gin route like /api/admin/users protected by an API key check in a middleware function. If an attacker registers a domain (e.g., evil.example) pointing to a public IP and later serves DNS responses that map that domain to 127.0.0.1, a victim who visits the attacker’s page can have their browser silently send authenticated requests to the local admin endpoint. The API key, which is typically stored in JavaScript or a browser session, is sent with those rebinding requests. From the perspective of Gin, the request is authenticated and authorized, even though the network origin has changed to a sensitive internal address. This can lead to unauthorized data access or actions if the handler does not also validate the effective network destination.

The interaction becomes more pronounced when API keys are passed via headers (e.g., X-API-Key) and when Gin routes assume that the remote IP is trustworthy after authentication. Standard middleware in Gin does not differentiate between an external client and a rebinding-induced internal IP; it only sees that the key is valid. If the API key is long-lived and the service does not pair it with per-request network validation, an attacker can chain DNS rebinding with Cross-Site Request Forgery (CSRF) to perform actions on internal management interfaces or sensitive microservices that are not exposed to the public internet.

In practice, this means that API key–based protection in Gin must not be treated as a network boundary. A handler that only checks for a valid API key and then trusts the request’s perceived origin is vulnerable when DNS rebinding is possible. Attackers can leverage this to reach endpoints such as /debug/pprof, internal health checks, or administrative APIs that were never intended for external or browser-based access. Because Gin does not inherently enforce network-level constraints, developers must explicitly ensure that requests are not only authenticated but also originate from expected network contexts.

Api Keys-Specific Remediation in Gin — concrete code fixes

To mitigate DNS rebinding in Gin when using API keys, combine proper key validation with network-aware checks and strict CORS policies. Avoid relying solely on header-based API key validation without verifying the request’s IP or host context. The following examples demonstrate secure patterns using real Gin code.

First, define a middleware that validates the API key and also inspects the request’s Host header and, where possible, the X-Forwarded-For or X-Real-IP headers. Do not assume that a valid key implies a safe origin.

package main

import (
    "net/http"
    "strings"

    "github.com/gin-gonic/gin"
)

// allowedHosts should be configured per deployment (e.g., via environment variables).
var allowedHosts = map[string]bool{
    "api.example.com": true,
    "app.example.com":  true,
}

// apiKeyMiddleware validates the API key and performs host validation.
func apiKeyMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        key := c.GetHeader("X-API-Key")
        if key == "" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing api key"})
            return
        }

        // Validate the key against a secure store (e.g., hashed in env or vault).
        if !isValidAPIKey(key) {
            c.AboutWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid api key"})
            return
        }

        // Host header validation to mitigate DNS rebinding.
        host := c.Request.Host
        if !allowedHosts[host] {
            c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "host not allowed"})
            return
        }

        c.Next()
    }
}

func isValidAPIKey(key string) bool {
    // In production, compare against a hashed value stored securely.
    expected := "example-secure-key-123"
    return subtleCompare(key, expected)
}

// subtleCompare prevents timing attacks.
func subtleCompare(a, b string) bool {
    return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
}

func main() {
    r := gin.Default()

    r.Use(apiKeyMiddleware())

    r.GET("/api/admin/users", func(c *gin.Context) {
        c.JSON(http.StatusOK, gin.H{"users": []string{"alice", "bob"}})
    })

    r.Run(":8080")
}

Second, enforce CORS strictly so that browser-based requests cannot arbitrarily change origin. Use a CORS middleware that limits origins, methods, and headers rather than allowing all origins.

import (
    "github.com/gin-contrib/cors"
)

func setupCORS() cors.Config {
    return cors.Config{
        AllowOrigins:     []string{"https://app.example.com"},
        AllowMethods:     []string{"GET", "POST"},
        AllowHeaders:     []string{"Origin", "Content-Length", "X-API-Key"},
        ExposeHeaders:    []string{"Content-Length"},
        AllowCredentials: true,
        MaxAge:           12 * time.Hour,
    }
}

func main() {
    r := gin.Default()
    r.Use(cors.New(setupCORS()))
    // routes and middleware...
    r.Run(":8080")
}

Third, avoid placing long-lived API keys in JavaScript where they can be exfiltrated during a rebinding attack. Instead, use short-lived tokens or session-bound credentials when possible, and validate tokens server-side with strict audience and issuer checks. Combine this with network validation so that even if a key is compromised, an attacker cannot use it to reach internal endpoints via rebinding.

These steps ensure that API keys in Gin are protected not only against leakage and misuse, but also against network-based attacks like DNS rebinding that exploit trust in authentication without considering endpoint context.

Frequently Asked Questions

Why is host header validation important when using API keys in Gin?
Host header validation prevents DNS rebinding attacks by ensuring that requests are only accepted from expected hostnames. Even with a valid API key, an attacker can use DNS rebinding to make a victim’s browser send authenticated requests to internal IPs if the server trusts the key alone. Validating the Host header blocks requests where the hostname does not match your configured domains.
Can CORS settings alone protect against DNS rebinding in Gin?
CORS settings in the browser prevent cross-origin requests from being processed by JavaScript, but they do not stop non-browser clients or server-side rebinding. CORS should be combined with server-side host validation and secure API key storage to fully mitigate DNS rebinding risks in Gin.