37 lines
989 B
Go
37 lines
989 B
Go
package proxy
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
var blockedHosts = map[string]struct{}{
|
|
"169.254.169.254": {},
|
|
"metadata.google.internal": {},
|
|
}
|
|
|
|
// ValidateURL applies MVP SSRF basics. Week 2 should add configurable CIDR
|
|
// deny-lists and DNS-rebinding protection before exposing this beyond localhost.
|
|
func ValidateURL(raw string) (*url.URL, error) {
|
|
u, err := url.Parse(raw)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid url: %w", err)
|
|
}
|
|
if u.Scheme != "http" && u.Scheme != "https" {
|
|
return nil, fmt.Errorf("only http/https schemes are allowed")
|
|
}
|
|
if u.Hostname() == "" {
|
|
return nil, fmt.Errorf("url host is required")
|
|
}
|
|
host := strings.ToLower(strings.TrimSuffix(u.Hostname(), "."))
|
|
if _, blocked := blockedHosts[host]; blocked {
|
|
return nil, fmt.Errorf("blocked metadata host")
|
|
}
|
|
if ip := net.ParseIP(host); ip != nil && ip.Equal(net.ParseIP("169.254.169.254")) {
|
|
return nil, fmt.Errorf("blocked metadata address")
|
|
}
|
|
return u, nil
|
|
}
|