HIGH dns cache poisoningfiberapi keys

Dns Cache Poisoning in Fiber with Api Keys

Dns Cache Poisoning in Fiber with Api Keys — how this specific combination creates or exposes the vulnerability

In a Fiber application, DNS cache poisoning can occur when an attacker manipulates DNS responses to redirect API calls to a malicious host. If the application relies on static API keys for authorization, those keys may be sent to the attacker-controlled endpoint, leading to credential theft or unauthorized access. This risk is especially relevant when API keys are resolved at startup or cached in environment variables without runtime validation.

Consider a scenario where https://api.external-service.com resolves via DNS to an attacker IP due to cache poisoning. The Fiber app makes outbound HTTP requests using API keys stored in environment variables. Because the DNS entry is poisoned, the request reaches the attacker, who can harvest the API keys and replay them against the legitimate service. This undermines the trust boundary that API keys are meant to enforce.

Additionally, if the Fiber application dynamically constructs request URLs using user input before appending API keys, and that input influences the hostname, the poisoning surface expands. For example, a hostname derived from a client-supplied parameter may be resolved via a compromised DNS resolver, causing the application to send API keys to an arbitrary host. Since DNS operates below the application layer, the vulnerability is not mitigated by HTTPS alone; the integrity of the hostname resolution is critical.

Middleware that logs outbound requests may inadvertently expose API keys if DNS poisoning redirects traffic to an attacker-controlled logging sink. Even with TLS, the attacker can present a valid certificate for the malicious host, and the Fiber app may trust it if certificate pinning is not enforced. This exposes API keys in transit and may allow session hijacking or lateral movement within the API ecosystem.

Because middleBrick scans the unauthenticated attack surface, it can detect indicators such as unusual outbound connections or missing hostname validation that may suggest DNS-related weaknesses. While the scanner does not fix runtime DNS behavior, its findings help prioritize mitigations like strict hostname verification and secure resolver configuration.

Api Keys-Specific Remediation in Fiber — concrete code fixes

To reduce DNS cache poisoning risks when using API keys in Fiber, validate hostnames programmatically and avoid reliance on potentially poisoned DNS for routing decisions. Below are concrete remediation examples using the Fiber framework and standard Go libraries.

1. Enforce hostname verification with custom dialer

Use a custom HTTP transport that verifies the resolved IP against an allowlist or fingerprint. This prevents requests to unexpected hosts even if DNS is poisoned.

import (
    "context"
    "crypto/tls"
    "net"
    "net/http"
    "time"

    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()

    // Define allowed IPs or hostnames
    allowedHosts := map[string][]string{
        "api.external-service.com": {"192.0.2.10", "198.51.100.20"},
    }

    dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
        // Perform DNS resolution
        ips, err := net.LookupIP("addr")
        if err != nil {
            return nil, err
        }
        // Validate against allowed list
        var ipList []string
        for _, ip := range ips {
            ipList = append(ipList, ip.String())
        }
        // Implement allowlist check (simplified)
        if !contains(allowedHosts["api.external-service.com"], ipList) {
            return nil, fmt.Errorf("disallowed IP resolved: %v", ipList)
        }
        conn, err := net.Dial(network, addr)
        if err != nil {
            return nil, err
        }
        return tls.Client(conn, &tls.Config{ServerName: "api.external-service.com"}), nil
    }

    client := &http.Client{
        Transport: &http.Transport{
            DialContext: dialContext,
            TLSClientConfig: &tls.Config{
                ServerName: "api.external-service.com",
            },
        },
        Timeout: 10 * time.Second,
    }

    app.Get("/fetch", func(c *fiber.Ctx) error {
        req, _ := http.NewRequestWithContext(c.UserContext(), "GET", "https://api.external-service.com/data", nil)
        req.Header.Set("Authorization", "Bearer "+os.Getenv("API_KEY"))
        resp, err := client.Do(req)
        if err != nil {
            return c.Status(fiber.StatusBadGateway).SendString("upstream validation failed")
        }
        defer resp.Body.Close()
        // process response
        return c.SendStatus(fiber.StatusOK)
    })

    app.Listen(":3000")
}

func contains(allow, resolved []string) bool {
    for _, ra := range resolved {
        for _, a := range allow {
            if ra == a {
                return true
            }
        }
    }
    return false
}

2. Secure API key usage with explicit header injection

Avoid constructing URLs with user-controlled host portions. Instead, use a static base URL and inject API keys via headers.

import (
    "net/http"

    "github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()
    apiKey := os.Getenv("API_KEY")
    if apiKey == "" {
        // fail closed
        panic("API_KEY environment variable not set")
    }

    app.Get("/proxy", func(c *fiber.Ctx) error {
        client := &http.Client{}
        req, err := http.NewRequest(http.MethodGet, "https://api.external-service.com/data", nil)
        if err != nil {
            return c.SendStatus(fiber.StatusBadRequest)
        }
        req.Header.Set("Authorization", "Bearer "+apiKey)
        // Ensure Host header is not user-controlled
        req.Host = "api.external-service.com"
        resp, err := client.Do(req)
        if err != nil {
            return c.SendStatus(fiber.StatusBadGateway)
        }
        defer resp.Body.Close()
        return c.SendStatus(fiber.StatusOK)
    })

    app.Listen(":3000")
}

3. Validate and pin public key pins for TLS

Use HTTP Public Key Pinning (HPKP) or TLS client configuration to reject unexpected certificates, reducing impact of DNS redirection.

import (
    "crypto/tls"
    "crypto/x509"
    "io/ioutil"
    "net/http"

    "github.com/gofiber/fiber/v2"
)

func main() {
    rootCAs := x509.NewCertPool()
    pem, err := ioutil.ReadFile("./api.external-service.com.pem")
    if err != nil {
        panic(err)
    }
    if ok := rootCAs.AppendCertsFromPEM(pem); !ok {
        panic("failed to append cert")
    }

    app := fiber.New()
    client := &http.Client{
        Transport: &http.Transport{
            TLSClientConfig: &tls.Config{
                RootCAs:            rootCAs,
                ServerName:         "api.external-service.com",
                InsecureSkipVerify: false,
            },
        },
    }

    app.Get("/secure", func(c *fiber.Ctx) error {
        req, _ := http.NewRequest("GET", "https://api.external-service.com/data", nil)
        req.Header.Set("Authorization", "Bearer "+os.Getenv("API_KEY"))
        resp, err := client.Do(req)
        if err != nil {
            return c.SendStatus(fiber.StatusBadGateway)
        }
        defer resp.Body.Close()
        return c.SendStatus(fiber.StatusOK)
    })

    app.Listen(":3000")
}

Frequently Asked Questions

Can DNS cache poisoning affect HTTPS requests in Fiber?
Yes, HTTPS protects content but not hostname integrity. If DNS resolution is poisoned, requests can be redirected to malicious hosts that present valid certificates, leading to API key exposure.
How does middleBrick help detect DNS-related weaknesses?
middleBrick scans the unauthenticated attack surface and can identify unusual outbound connections or missing hostname validation patterns that may indicate DNS-related risks, guiding prioritization of fixes.