Dns Rebinding in Gin with Hmac Signatures
Dns Rebinding in Gin with Hmac Signatures — how this specific combination creates or exposes the vulnerability
DNS Rebinding is an attack that manipulates DNS responses to make a client believe a malicious host is a trusted origin. In a Gin-based backend that relies on Hmac Signatures for request authentication, this interaction can bypass intended origin checks if verification logic is incomplete.
Consider a Gin service that validates Hmac Signatures to ensure requests originate from a trusted source. The server may check a X-API-Key header and verify the Hmac without also enforcing strict source IP or hostname requirements. An attacker can craft a scenario where a victim’s browser, authenticated via session cookie or API key, sends requests to a domain that initially resolves to a benign IP but later rebinds to an internal service (e.g., 127.0.0.1 or an internal API endpoint). Because the Hmac Signature is computed over request data without tying it to a specific network endpoint, the server may still accept the request, interpreting it as valid.
For example, a compromised web page can repeatedly resolve a domain like trusted.example.com to 203.0.113.1 and then to 127.0.0.1. If the Gin handler only validates the Hmac Signature and does not verify that the request targets the intended service or that the connection originates from an expected network zone, the rebinding can allow an attacker to interact with internal endpoints that were assumed to be inaccessible. This becomes particularly risky when the Hmac check is performed on the client side or relayed through a proxy that does not enforce the same network constraints.
In this configuration, the Hmac Signature ensures data integrity and authenticity between the client and server, but it does not inherently prevent the client from being redirected to a different server or IP. Without additional controls—such as strict host header validation, IP allowlisting, or mutual TLS—the combination of DNS Rebinding and Hmac Signatures in Gin can expose endpoints that should only be reachable from specific network contexts.
Hmac Signatures-Specific Remediation in Gin — concrete code fixes
To mitigate DNS Rebinding risks while using Hmac Signatures in Gin, you must couple cryptographic verification with network and host validation. Below are concrete, working examples that demonstrate how to implement Hmac Signature verification alongside host and IP checks.
1. Hmac Signature Verification in Gin
The following snippet shows how to validate an Hmac Signature in a Gin handler. The signature is computed over selected headers, the request path, and the body using Hmac-SHA256. The server compares the computed signature with the one provided in a custom header, rejecting mismatches.
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
const sharedSecret = "your-secure-shared-secret"
func verifyHmac(c *gin.Context) {
providedSignature := c.GetHeader("X-API-Signature")
if providedSignature == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing signature"})
return
}
var payloadBody string
if c.Request.Body != nil {
// In production, ensure you handle body reading carefully to avoid exhausting memory
bodyBytes, err := io.ReadAll(c.Request.Body)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": "failed to read body"})
return
}
payloadBody = string(bodyBytes)
// Restore body for further use if needed
c.Request.Body = io.NopCloser(strings.NewReader(payloadBody))
}
message := c.Request.Method + "\n" + c.Request.URL.Path + "\n" + payloadBody
key := []byte(sharedSecret)
mac := hmac.New(sha256.New, key)
mac.Write([]byte(message))
expectedSignature := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(expectedSignature), []byte(providedSignature)) {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "invalid signature"})
return
}
c.Next()
}
func main() {
r := gin.Default()
r.Use(gin.Logger())
r.Use(verifyHmac)
r.POST("/api/resource", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
})
r.Run(":8080")
}
2. Combining Hmac with Host and IP Validation
To defend against DNS Rebinding, explicitly validate the Host header and, where possible, restrict source IP ranges. The example below adds host verification to the middleware chain.
func verifyHost(allowedHosts []string) gin.HandlerFunc {
return func(c *gin.Context) {
host := c.Request.Host
valid := false
for _, h := range allowedHosts {
if host == h {
valid = true
break
}
}
if !valid {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "host not allowed"})
return
}
c.Next()
}
}
func main() {
r := gin.Default()
r.Use(gin.Logger())
r.Use(verifyHmac)
r.Use(verifyHost([]string{"api.example.com:8080"}))
r.POST("/api/resource", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"status": "ok"})
})
r.Run(":8080")
}
In production, you may also incorporate IP allowlisting at the network or middleware layer. These measures ensure that even if DNS is manipulated, requests that do not originate from expected hosts or networks are rejected, neutralizing the impact of DNS Rebinding when combined with Hmac Signatures.