HIGH ssrf server sideecho go

Ssrf Server Side in Echo Go

How SSRF Server-Side Manifests in Echo Go

SSRF (Server-Side Request Forgery) in Echo Go applications typically occurs when the server makes outbound HTTP requests based on user-controlled input without proper validation. In Echo Go, this vulnerability manifests through several common patterns that Echo developers should recognize.

The most frequent SSRF vector in Echo Go is the HTTP client usage pattern. When developers use Go's standard net/http library or third-party clients to make requests to URLs provided by users, they create an attack surface. For example:

func handleRequest(c echo.Context) error {
    url := c.QueryParam("url")
    resp, err := http.Get(url) // Vulnerable: user controls URL
    if err != nil {
        return c.JSON(http.StatusInternalServerError, err.Error())
    }
    defer resp.Body.Close()
    
    body, _ := ioutil.ReadAll(resp.Body)
    return c.JSON(http.StatusOK, string(body))
}

This pattern is dangerous because an attacker can supply internal URLs like http://localhost:8080, http://169.254.169.254 (AWS metadata), or http://internal.service:8080, allowing them to access internal services, cloud metadata APIs, or perform port scanning.

Echo Go applications often expose SSRF through proxy functionality, webhook handlers, or API aggregation services. Another common pattern involves using echo.Context.Request() to forward requests:

func proxyRequest(c echo.Context) error {
    targetURL := c.QueryParam("target")
    req, _ := http.NewRequest("GET", targetURL, nil)
    
    client := &http.Client{}
    resp, err := client.Do(req) // Vulnerable to SSRF
    if err != nil {
        return c.JSON(http.StatusBadGateway, err.Error())
    }
    defer resp.Body.Close()
    
    return c.Stream(resp.StatusCode, resp.Header.Get("Content-Type"), resp.Body)
}

Echo Go's middleware ecosystem can also introduce SSRF risks. Custom middleware that makes external requests based on request headers or parameters, or services that fetch external resources for content processing, create similar vulnerabilities.

Echo Go-Specific Detection

Detecting SSRF in Echo Go applications requires both static code analysis and runtime scanning. For static detection, look for these Echo Go-specific patterns:

Code Pattern Analysis: Search your Echo Go codebase for HTTP client usage where URLs come from user input. Use grep or your IDE to find patterns like:

grep -r "http\.Get(" . | grep -E "(c\.QueryParam|c\.Param|c\.FormValue)"
grep -r "http\.Client" . | grep -E "(c\.QueryParam|c\.Param|c\.FormValue)"

Echo Context Parameter Extraction: Focus on these Echo-specific methods that extract user input:

c.QueryParam("url")
c.Param("id")
c.FormValue("redirect")
c.Request().Header.Get("X-Forwarded-For")

Runtime Testing with middleBrick: middleBrick's black-box scanning approach is particularly effective for Echo Go applications. Since Echo Go apps typically run on standard HTTP ports, you can scan your API endpoints directly:

middlebrick scan https://yourechoapp.com/api/endpoint

middleBrick tests for SSRF by attempting to access internal resources, cloud metadata endpoints, and non-routable IP addresses. It specifically checks for:

  • Access to localhost and 127.0.0.1
  • Private IP ranges (10.x, 172.16-31.x, 192.168.x)
  • Cloud metadata services (169.254.169.254, 169.254.170.2)
  • Non-routable addresses (0.0.0.0, 255.255.255.255)

Echo Go Middleware Inspection: Review your middleware chain for any components that make external requests. Echo Go's middleware structure makes this straightforward:

e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.CORS())
// Check if any middleware makes external requests

Network Layer Detection: Use network monitoring tools during testing to observe outbound connections from your Echo Go application. Tools like Wireshark or tcpdump can reveal if your application is making unexpected external requests.

Echo Go-Specific Remediation

Remediating SSRF in Echo Go applications requires a defense-in-depth approach using Go's native capabilities and Echo Go's features. Here are Echo Go-specific remediation strategies:

URL Validation with net/url: Always validate and sanitize URLs before making requests. Echo Go developers should use Go's standard library for robust validation:

import (
    "net/url"
    "strings"
)

func validateURL(rawURL string) (string, error) {
    parsedURL, err := url.Parse(rawURL)
    if err != nil {
        return "", err
    }
    
    // Block private IP ranges
    if isPrivateIP(parsedURL.Hostname()) {
        return "", errors.New("private IP addresses are not allowed")
    }
    
    // Block localhost
    if strings.HasPrefix(parsedURL.Hostname(), "localhost") || 
       parsedURL.Hostname() == "127.0.0.1" {
        return "", errors.New("localhost addresses are not allowed")
    }
    
    // Block cloud metadata endpoints
    if parsedURL.Hostname() == "169.254.169.254" || 
       parsedURL.Hostname() == "169.254.170.2" {
        return "", errors.New("cloud metadata access is not allowed")
    }
    
    return parsedURL.String(), nil
}

func isPrivateIP(host string) bool {
    ip := net.ParseIP(host)
    if ip == nil {
        return false
    }
    
    return ip.IsPrivate() || ip.IsLoopback() || ip.IsUnspecified()
}

Echo Go Context Validation Middleware: Create reusable middleware for Echo Go that validates all incoming request parameters:

func SSRFValidationMiddleware() echo.MiddlewareFunc {
    return func(next echo.HandlerFunc) echo.HandlerFunc {
        return func(c echo.Context) error {
            // Check query parameters
            for _, param := range c.QueryParams() {
                if isPotentiallyDangerousURL(param) {
                    return echo.NewHTTPError(http.StatusBadRequest, "invalid URL parameter")
                }
            }
            
            // Check path parameters
            for _, param := range c.ParamValues() {
                if isPotentiallyDangerousURL(param) {
                    return echo.NewHTTPError(http.StatusBadRequest, "invalid path parameter")
                }
            }
            
            return next(c)
        }
    }
}

func isPotentiallyDangerousURL(input string) bool {
    // Simple check for URL-like patterns
    lower := strings.ToLower(input)
    return strings.Contains(lower, "http://") || 
           strings.Contains(lower, "https://") ||
           strings.Contains(lower, "localhost") ||
           strings.Contains(lower, "127.0.0.1")
}

Safe HTTP Client Configuration: When making external requests in Echo Go, configure safe defaults:

import (
    "net"
    "net/http"
    "time"
)

func createSafeHTTPClient() *http.Client {
    return &http.Client{
        Timeout: 10 * time.Second, // Prevent slowloris attacks
        Transport: &http.Transport{
            DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
                // Custom dialer to block private networks
                host, _, err := net.SplitHostPort(addr)
                if err != nil {
                    return nil, err
                }
                
                if isPrivateIP(host) {
                    return nil, errors.New("connection to private network denied")
                }
                
                return net.Dial(network, addr)
            },
            // Additional security configurations
            DisableKeepAlives: true,
            MaxIdleConns: 10,
        },
    }
}

Echo Go-Specific Allowlist Approach: For applications that need to make external requests, implement an allowlist of approved domains:

var allowedDomains = map[string]bool{
    "api.example.com": true,
    "webhook.example.com": true,
}

func makeSafeRequest(c echo.Context) error {
    target := c.QueryParam("target")
    
    parsedURL, err := url.Parse(target)
    if err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, "invalid URL format")
    }
    
    if !allowedDomains[parsedURL.Hostname()] {
        return echo.NewHTTPError(http.StatusForbidden, "domain not allowed")
    }
    
    client := createSafeHTTPClient()
    resp, err := client.Get(target)
    if err != nil {
        return echo.NewHTTPError(http.StatusBadGateway, "external service error")
    }
    defer resp.Body.Close()
    
    return c.Stream(resp.StatusCode, resp.Header.Get("Content-Type"), resp.Body)
}

Echo Go Testing Integration: Add SSRF-specific tests to your Echo Go test suite:

func TestSSRFValidation(t *testing.T) {
    e := echo.New()
    
    // Test with malicious URLs
    testCases := []struct {
        input    string
        expected int
    }{
        {"http://localhost/test", http.StatusBadRequest},
        {"http://169.254.169.254/metadata", http.StatusBadRequest},
        {"http://10.0.0.1/test", http.StatusBadRequest},
        {"http://valid.example.com/api", http.StatusOK},
    }
    
    for _, tc := range testCases {
        req := httptest.NewRequest(http.MethodGet, "/test?url="+tc.input, nil)
        rec := httptest.NewRecorder()
        
        // Apply SSRF validation middleware
        err := SSRFValidationMiddleware()(func(c echo.Context) error {
            return c.String(http.StatusOK, "ok")
        })(echo.NewContext(req, rec))
        
        if err != nil && err.(*echo.HTTPError).Code != tc.expected {
            t.Errorf("Expected %d for %s, got %v", tc.expected, tc.input, err)
        }
    }
}

Frequently Asked Questions

How can I test my Echo Go application for SSRF vulnerabilities?
Use middleBrick's black-box scanning by running 'middlebrick scan https://yourechoapp.com' to test for SSRF vulnerabilities. Additionally, implement unit tests that attempt to access internal resources, cloud metadata endpoints, and private IP addresses. Use Go's testing package with httptest to simulate malicious requests and verify your validation logic blocks them.
What's the difference between SSRF and open redirect in Echo Go applications?
SSRF allows attackers to make the server request internal or external resources, potentially accessing internal APIs, cloud metadata, or performing port scanning. Open redirect only changes where the client is sent after a request completes. In Echo Go, SSRF involves HTTP clients making outbound requests (http.Get, http.Client), while open redirect manipulates Location headers or response URLs. Both are serious but SSRF typically has broader impact as it can access internal services the client cannot reach.