Dns Rebinding in Fiber with Api Keys
Dns Rebinding in Fiber with Api Keys — how this specific combination creates or exposes the vulnerability
DNS rebinding is a client-side network attack that manipulates DNS responses to make a victim’s browser believe a malicious domain resolves to an internal IP address, such as 127.0.0.1 or a private service endpoint. When an API protected only by API keys is exposed from a Fiber application to the broader network, this combination can allow an attacker to bypass same-origin policies and reach internal endpoints that were assumed to be inaccessible from the web.
In Fiber, API keys are typically validated via middleware before routing requests to handlers. If an endpoint accepts API keys in headers or query parameters and does not enforce strict source origin checks or network exposure rules, an attacker can serve a malicious webpage that performs DNS rebinding to your domain. The victim’s browser will include the API key in requests (e.g., via cookies or headers) because the origin appears to match the application’s domain, while the rebinding directs traffic to an internal admin interface or management API that would otherwise be protected by firewall rules.
Consider a Fiber service that binds to 0.0.0.0 and exposes an OpenAPI spec at /docs. If the service uses API key authentication without additional network segregation, an endpoint like GET /internal/status might be reachable from the internet due to the rebinding-induced routing. The attacker’s page triggers a request to https://your-service.example.com/internal/status with the victim’s API key, and because the key is validated but the endpoint’s network context is not, the attacker can read sensitive responses that should never be exposed to external clients.
This scenario is especially relevant when API keys are passed in headers such as X-API-Key without additional transport protections or strict CORS policies. DNS rebinding does not require the attacker to compromise TLS or steal keys directly; it exploits the trust placed in the key alone and the assumption that internal endpoints are not reachable once the key is presented.
middleBrick scans can detect this by correlating OpenAPI spec exposure with runtime behavior. For example, if an endpoint defined in the spec is reachable from unexpected network contexts during black-box testing, and API key validation does not include origin or referer checks, the scan can flag the risk alongside findings from the Authentication and Input Validation checks.
Api Keys-Specific Remediation in Fiber — concrete code fixes
Securing API keys in Fiber requires combining proper middleware usage with network and transport hardening. Below are concrete, idiomatic Go examples that address DNS rebinding risks specifically related to API key validation.
1. Validate API keys and enforce strict origin checks
Do not rely solely on the presence of an API key. Add CORS and referer/origin validation to ensure requests originate from trusted sources. This reduces the window for DNS rebinding to internal services.
package main
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
)
func main() {
app := fiber.New()
// Configure CORS to allow only your frontend origins
app.Use(cors.New(cors.Config{
AllowOrigins: "https://app.yourcompany.com,https://admin.yourcompany.com",
AllowCredentials: true,
}))
// API key validation middleware with referer/origin check
app.Use(func(c *fiber.Ctx) error {
apiKey := c.Get("X-API-Key")
if apiKey == "" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "missing api key"})
}
// Optionally validate against a secure store or constant-time compare
if !isValidKey(apiKey) {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "invalid api key"})
}
// Additional check: ensure Origin or Referer is from your trusted domains
origin := c.Get("Origin")
referer := c.Get("Referer")
if !isTrustedOrigin(origin, referer) {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "invalid request origin"})
}
return c.Next()
})
app.Get("/internal/status", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "ok", "internal": false})
})
app.Listen(":3000")
}
func isValidKey(key string) bool {
// Use constant-time comparison in production
return key == "YOUR_STRONG_API_KEY"
}
func isTrustedOrigin(origin, referer string) bool {
allowed := map[string]bool{
"https://app.yourcompany.com": true,
"https://admin.yourcompany.com": true,
}
if origin == "" && referer == "" {
return false
}
return allowed[origin] || allowed[referer]
}
2. Avoid exposing sensitive endpoints publicly
Even with API keys, avoid binding administrative or internal endpoints to 0.0.0.0 if they do not need to be publicly reachable. Use network-level separation and explicit route guards.
package main
import (
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New()
// Public API with API key
public := app.Group("/api")
public.Use(apiKeyMiddleware())
public.Get("/status", publicStatus)
// Admin API on a separate route group with stricter constraints
admin := app.Group("/admin")
admin.Use(apiKeyMiddleware())
admin.Use(adminOriginMiddleware()) // stricter origin checks
admin.Get("/metrics", adminMetrics)
// Listen only on localhost if admin endpoints should not be externally reachable
go app.Listen(":3000") // public interface
// admin group could be served on 127.0.0.1:8080 in a separate process or container
// Listen for admin on localhost only
// app.Listen("127.0.0.1:8080")
}
func apiKeyMiddleware() fiber.Handler {
return func(c *fiber.Ctx) error {
if c.Get("X-API-Key") != "PUBLIC_KEY" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "unauthorized"})
}
return c.Next()
}
}
func adminOriginMiddleware() fiber.Handler {
return func(c *fiber.Ctx) error {
if c.Get("Origin") != "https://admin.yourcompany.com" {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "admin origin required"})
}
return c.Next()
}
}
func publicStatus(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "public ok"})
}
func adminMetrics(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"metrics": "admin only"})
}
3. Use environment-based configuration and secret management
Do not hardcode API keys. Use environment variables and ensure secrets are rotated regularly. This limits exposure if keys are accidentally logged or exposed via DNS rebinding or other means.
package main
import (
"os"
"github.com/joho/godotenv"
"github.com/gofiber/fiber/v2"
)
func main() {
// Load .env safely in development; rely on environment in production
_ = godotenv.Load()
apiKey := os.Getenv("API_KEY")
if apiKey == "" {
panic("API_KEY environment variable is required")
}
app := fiber.New()
app.Use(func(c *fiber.Ctx) error {
if c.Get("X-API-Key") != apiKey {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "invalid key"})
}
return c.Next()
})
app.Get("/protected", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"data": "secure"})
})
app.Listen(":3000")
}
These steps ensure that API key validation is combined with transport and origin controls, reducing the risk that DNS rebinding can exploit trusted keys to reach internal endpoints.