Ssrf Server Side in Fiber
How SSRF Manifests in Fiber Applications
Server-Side Request Forgery (SSRF) in Fiber applications occurs when an attacker can manipulate internal HTTP requests made by the server. In Fiber, this typically happens when user-controlled input is passed directly to HTTP client functions without proper validation.
The most common Fiber SSRF patterns involve the fasthttp client or third-party libraries making outbound requests. Consider this vulnerable Fiber endpoint:
app := fiber.New()This endpoint allows an attacker to make the server request any URL, including internal services, cloud metadata endpoints, or external resources. The /proxy route accepts a url parameter and forwards it to the fasthttp client without validation.
Common SSRF attack vectors in Fiber include:
- Internal network enumeration:
http://192.168.1.1,http://localhost:8080 - Cloud metadata services:
http://169.254.169.254/latest/meta-data/(AWS),http://metadata.google.internal/computeMetadata/v1/(GCP) - Port scanning:
http://localhost:22,http://internal-db:3306 - Protocol smuggling:
file:///etc/passwd,gopher://localhost:25
Another Fiber-specific SSRF pattern involves database connections or Redis clients where connection strings come from user input:
app.Post("/connect-db", func(c *fiber.Ctx) error {
dsn := c.FormValue("dsn")
db, err := sql.Open("mysql", dsn)
// ...
})
Here, an attacker could manipulate the DSN to connect to internal databases or services the application server can access but are not publicly exposed.
Fiber-Specific Detection Methods
Detecting SSRF in Fiber requires both static analysis and runtime scanning. For static analysis, look for patterns where user input flows to HTTP clients or connection functions:
// Vulnerable patterns to search for
go func() {
client := &fasthttp.Client{}
req := fasthttp.AcquireRequest()
req.SetRequestURI(c.Query("target"))
// ...
}()
middleBrick's Fiber-specific scanning identifies these patterns by analyzing the runtime behavior of your endpoints. When you scan a Fiber application with middleBrick, it:
- Identifies all HTTP endpoints that accept URL parameters
- Attempts controlled SSRF payloads against each endpoint
- Detects successful internal service connections
- Checks for cloud metadata service access
- Tests for protocol smuggling attempts
The scanner uses a comprehensive payload set including:
http://localhost:8080
http://127.0.0.1:3306
http://169.254.169.254/latest/meta-data/
http://metadata.google.internal/computeMetadata/v1/
file:///etc/passwd
gopher://localhost:25
For Fiber applications, middleBrick also analyzes OpenAPI specifications if provided, cross-referencing documented endpoints with actual runtime behavior to identify discrepancies that might indicate SSRF vulnerabilities.
CLI usage for scanning a Fiber API:
middlebrick scan https://your-fiber-app.com/api/proxy
The scan completes in 5-15 seconds and returns a security score with specific SSRF findings, including the exact payloads that succeeded and the internal services they accessed.
Fiber-Specific Remediation Techniques
Remediating SSRF in Fiber applications requires a defense-in-depth approach. The most effective strategy combines input validation, allowlisting, and network segmentation.
First, implement strict URL validation using a allowlist approach:
import (
"net/url"
"strings"
)
var allowedDomains = map[string]bool{
"api.example.com": true,
"cdn.example.org": true,
}
func validateURL(rawURL string) (string, error) {
u, err := url.Parse(rawURL)
if err != nil {
return "", err
}
// Block private IP ranges
if isPrivateIP(u.Hostname()) {
return "", errors.New("private IP not allowed")
}
// Block cloud metadata services
if isCloudMetadata(u.Hostname()) {
return "", errors.New("cloud metadata access denied")
}
// Check allowlist
if !allowedDomains[strings.ToLower(u.Hostname())] {
return "", errors.New("domain not in allowlist")
}
return rawURL, nil
}
func isPrivateIP(host string) bool {
// Check for private IP ranges (RFC 1918)
return strings.HasPrefix(host, "10.") ||
strings.HasPrefix(host, "172.16.") ||
strings.HasPrefix(host, "192.168.") ||
host == "localhost" || host == "127.0.0.1"
}
func isCloudMetadata(host string) bool {
return host == "169.254.169.254" ||
host == "metadata.google.internal" ||
host == "169.254.169.254"
}
Apply this validation in your Fiber endpoints:
app.Post("/safe-proxy", func(c *fiber.Ctx) error {
rawURL := c.Query("url")
validatedURL, err := validateURL(rawURL)
if err != nil {
return c.Status(fiber.StatusBadRequest).JSON(
fiber.Map{"error": err.Error()})
}
// Safe to make the request
client := &fasthttp.Client{}
req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)
req.SetRequestURI(validatedURL)
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)
if err := client.Do(req, resp); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(
fiber.Map{"error": err.Error()})
}
return c.Status(resp.StatusCode()).Send(resp.Body())
})
For database connections and other service integrations, use configuration files rather than user input:
type Config struct {
DatabaseDSN string `yaml:"database_dsn"`
RedisURL string `yaml:"redis_url"`
}
var config Config
func init() {
// Load from secure config file, not user input
yamlFile, err := ioutil.ReadFile("config.yaml")
if err != nil {
log.Fatal(err)
}
err = yaml.Unmarshal(yamlFile, &config)
if err != nil {
log.Fatal(err)
}
}
app.Post("/connect", func(c *fiber.Ctx) error {
// Use pre-configured connection strings
db, err := sql.Open("mysql", config.DatabaseDSN)
// ...
})
Additionally, implement network-level controls using Docker or firewall rules to restrict outbound connections to only necessary services, providing an additional layer of protection even if SSRF vulnerabilities exist in the code.