Ssrf Server Side in Fiber with Hmac Signatures
Ssrf Server Side in Fiber with Hmac Signatures — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in Go Fiber applications that use HMAC signatures can arise when a signed route parameter or header is used to select an outbound HTTP target without strict validation. For example, an endpoint may accept a signed url query parameter that is validated with a per-request HMAC before the application performs an HTTP request on the provided value. If the application trusts the signature but does not also enforce a strict allowlist of destinations, an attacker can supply a maliciously signed URL pointing to an internal service (e.g., http://127.0.0.1:8080/metadata) or to cloud metadata endpoints (e.g., http://169.254.169.254/latest/meta-data/), and the HMAC verification will pass because the server generated the signature for the attacker-supplied input.
In Fiber, this often occurs when custom middleware validates an HMAC over query parameters or headers to prevent tampering, but the server-side HTTP client uses the validated parameter directly as the request target. An attacker who cannot forge the HMAC might still exploit business logic that embeds user input into the destination URL, especially if the signature is computed over only a subset of parameters (e.g., an id) while the target host is supplied separately and not validated. A common pattern is a webhook callback where the signature ensures integrity of the callback URL, but the application does not restrict the host or path, enabling SSRF against internal endpoints or third-party services reachable from the server.
The combination of HMAC-based integrity checks and flexible outbound requests can therefore create a false sense of security: the signature prevents tampering with the signed fields, but it does not prevent the signed data from pointing to an undesirable destination. If the application resolves hostnames without restricting schemes, ports, or internal IP ranges, SSRF can be chained with other issues such as insecure deserialization or unsafe consumption of user-controlled URLs. Because SSRF can lead to metadata exposure, port scanning from the server, or access to cloud instance metadata, this pattern demands explicit destination allowlisting and careful schema validation before any network call is made.
Hmac Signatures-Specific Remediation in Fiber — concrete code fixes
To remediate SSRF when HMAC signatures are used in Fiber, ensure that the data used to form the outbound request is not solely derived from the signed input. Apply allowlisting for hosts, ports, and schemes, and treat the HMAC as integrity protection rather than authorization to reach arbitrary destinations. Below are concrete, working examples that demonstrate secure handling in Go Fiber.
Example 1: Signed callback URL with host and scheme allowlist
Compute the HMAC over a subset of parameters, then validate the target host and scheme against an allowlist before performing the request.
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/url"
"strings"
"github.com/gofiber/fiber/v2"
)
var secretKey = []byte("super-secret-key")
// allowedHosts is a strict allowlist of destinations
var allowedHosts = map[string]bool{
"api.example.com": true,
"webhook.example.com": true,
}
// allowedSchemes restricts protocols
var allowedSchemes = map[string]bool{
"https": true,
}
func computeHmac(data string) string {
h := hmac.New(sha256.New, secretKey)
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}
func verifyHmac(data, receivedMac string) bool {
expected := computeHmac(data)
return hmac.Equal([]byte(expected), []byte(receivedMac))
}
func main() {
app := fiber.New()
app.Get("/callback", func(c *fiber.Ctx) error {
rawURL := c.Query("url")
receivedMac := c.Query("mac")
dataToSign := "url=" + rawURL
if !verifyHmac(dataToSign, receivedMac) {
return c.Status(fiber.StatusBadRequest).SendString("invalid signature")
}
parsed, err := url.Parse(rawURL)
if err != nil {
return c.Status(fiber.StatusBadRequest).SendString("invalid url")
}
if !allowedSchemes[parsed.Scheme] {
return c.Status(fiber.StatusBadRequest).SendString("scheme not allowed")
}
if !allowedHosts[parsed.Host] {
return c.Status(fiber.StatusBadRequest).SendString("host not allowed")
}
// Safe to use parsed.RequestURI() or build a new URL with validated components
client := &http.Client{}
req, _ := http.NewRequest(http.MethodGet, parsed.String(), nil)
resp, err := client.Do(req)
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString("request failed")
}
defer resp.Body.Close()
return c.SendStatus(fiber.StatusOK)
})
app.Listen(":3000")
}
Example 2: HMAC over multiple fields with explicit destination
Sign multiple fields including an intended destination ID, then map that ID to a concrete, validated endpoint.
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"net/http"
"github.com/gofiber/fiber/v2"
)
var secretKey = []byte("super-secret-key")
var allowedEndpoints = map[string]string{
"user_profile": "https://api.example.com/profile",
"account_info": "https://api.example.com/account",
}
func computeHmac(fields ...string) string {
h := hmac.New(sha256.New, secretKey)
for _, f := range fields {
h.Write([]byte(f))
}
return hex.EncodeToString(h.Sum(nil))
}
func main() {
app := fiber.New()
app.Get("/resource", func(c *fiber.Ctx) error {
id := c.Query("id")
endpointKey := c.Query("key")
receivedMac := c.Query("mac")
expectedMac := computeHmac(endpointKey, id)
if !hmac.Equal([]byte(expectedMac), []byte(receivedMac)) {
return c.Status(fiber.StatusBadRequest).SendString("invalid signature")
}
target, ok := allowedEndpoints[endpointKey]
if !ok {
return c.Status(fiber.StatusBadRequest).SendString("endpoint not allowed")
}
client := &http.Client{}
req, _ := http.NewRequest(http.MethodGet, target+"?id="+id, nil)
resp, err := client.Do(req)
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString("request failed")
}
defer resp.Body.Close()
return c.SendStatus(fiber.StatusOK)
})
app.Listen(":3000")
}
These examples emphasize that HMACs should protect integrity of selected parameters while the application independently validates the destination. By combining signature verification with host/scheme allowlists and explicit endpoint mapping, SSRF risks are substantially reduced without removing HMAC-based integrity checks.