mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-11 12:18:59 +00:00
fix(security): block 198.18.0.0/15 and 240.0.0.0/4 in SSRF protection (#1269)
Add RFC 2544 benchmarking range (198.18.0.0/15) and reserved range (240.0.0.0/4) to both SSRF blocklists (security package + web_fetch tool) to prevent internal network access via these special-use IPs. Closes #1218
This commit is contained in:
1 parent
505b7a9d99
commit
12a0168271
4 files changed
+68
-1
No files matched your search
@@ -52,6 +52,10 @@ func init() {
|
||||
"172.16.0.0/12",
|
||||
"192.168.0.0/16",
|
||||
"fc00::/7",
|
||||
// Benchmarking (RFC 2544)
|
||||
"198.18.0.0/15",
|
||||
// Reserved for future use
|
||||
"240.0.0.0/4",
|
||||
// Multicast
|
||||
"224.0.0.0/4",
|
||||
"ff00::/8",
|
||||
|
||||
@@ -45,6 +45,20 @@ func TestValidate_RejectsRFC1918(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate_RejectsBenchmarking(t *testing.T) {
|
||||
_, _, err := Validate("http://198.18.1.1/")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for benchmarking range (198.18.0.0/15), got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate_RejectsReserved(t *testing.T) {
|
||||
_, _, err := Validate("http://240.1.2.3/")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for reserved range (240.0.0.0/4), got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate_RejectsMulticast(t *testing.T) {
|
||||
_, _, err := Validate("http://224.0.0.1/")
|
||||
if err == nil {
|
||||
|
||||
@@ -131,7 +131,9 @@ func isPrivateIP(ipStr string) bool {
|
||||
{"169.254.0.0", 16}, // link-local
|
||||
{"172.16.0.0", 12}, // private
|
||||
{"192.168.0.0", 16}, // private
|
||||
{"100.64.0.0", 10}, // carrier-grade NAT
|
||||
{"100.64.0.0", 10}, // carrier-grade NAT (RFC 6598)
|
||||
{"198.18.0.0", 15}, // benchmarking (RFC 2544)
|
||||
{"240.0.0.0", 4}, // reserved for future use
|
||||
}
|
||||
|
||||
for _, r := range privateRanges {
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package tools
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestIsPrivateIP(t *testing.T) {
|
||||
blocked := []struct {
|
||||
ip string
|
||||
desc string
|
||||
}{
|
||||
{"10.0.0.1", "RFC 1918 class A"},
|
||||
{"172.16.5.1", "RFC 1918 class B"},
|
||||
{"192.168.1.1", "RFC 1918 class C"},
|
||||
{"127.0.0.1", "loopback"},
|
||||
{"169.254.169.254", "link-local / cloud metadata"},
|
||||
{"100.64.0.1", "carrier-grade NAT"},
|
||||
{"198.18.1.1", "benchmarking (RFC 2544)"},
|
||||
{"198.19.255.1", "benchmarking upper (RFC 2544)"},
|
||||
{"240.1.2.3", "reserved for future use"},
|
||||
{"255.255.255.255", "reserved broadcast"},
|
||||
{"::1", "IPv6 loopback"},
|
||||
{"fe80::1", "IPv6 link-local"},
|
||||
{"fc00::1", "IPv6 unique local"},
|
||||
}
|
||||
for _, tc := range blocked {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if !isPrivateIP(tc.ip) {
|
||||
t.Errorf("expected %s (%s) to be blocked", tc.ip, tc.desc)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
allowed := []struct {
|
||||
ip string
|
||||
desc string
|
||||
}{
|
||||
{"8.8.8.8", "Google DNS"},
|
||||
{"93.184.216.34", "example.com"},
|
||||
{"198.51.100.1", "public IP near benchmarking range"},
|
||||
}
|
||||
for _, tc := range allowed {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if isPrivateIP(tc.ip) {
|
||||
t.Errorf("expected %s (%s) to be allowed", tc.ip, tc.desc)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user