Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
e2807c5f
authored
Apr 17, 2026
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: enhance SSRF protection
parent
28347402
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
71 additions
and
27 deletions
+71
-27
common/ssrf_protection.go
+71
-27
No files found.
common/ssrf_protection.go
View file @
e2807c5f
...
@@ -29,45 +29,89 @@ var DefaultSSRFProtection = &SSRFProtection{
...
@@ -29,45 +29,89 @@ var DefaultSSRFProtection = &SSRFProtection{
AllowedPorts
:
[]
int
{},
AllowedPorts
:
[]
int
{},
}
}
// isPrivateIP 检查IP是否为私有地址
// privateIPv4Nets IPv4 私有/保留/特殊用途网段
// 参考 IANA IPv4 Special-Purpose Address Registry
// https://www.iana.org/assignments/iana-ipv4-special-registry/
var
privateIPv4Nets
=
[]
net
.
IPNet
{
{
IP
:
net
.
IPv4
(
0
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
8
,
32
)},
// 0.0.0.0/8 ("This network" / 未指定)
{
IP
:
net
.
IPv4
(
10
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
8
,
32
)},
// 10.0.0.0/8 (私有)
{
IP
:
net
.
IPv4
(
100
,
64
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
10
,
32
)},
// 100.64.0.0/10 (运营商级 NAT / CGNAT)
{
IP
:
net
.
IPv4
(
127
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
8
,
32
)},
// 127.0.0.0/8 (回环)
{
IP
:
net
.
IPv4
(
169
,
254
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
16
,
32
)},
// 169.254.0.0/16 (链路本地)
{
IP
:
net
.
IPv4
(
172
,
16
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
12
,
32
)},
// 172.16.0.0/12 (私有)
{
IP
:
net
.
IPv4
(
192
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
24
,
32
)},
// 192.0.0.0/24 (IETF 协议分配)
{
IP
:
net
.
IPv4
(
192
,
0
,
2
,
0
),
Mask
:
net
.
CIDRMask
(
24
,
32
)},
// 192.0.2.0/24 (TEST-NET-1)
{
IP
:
net
.
IPv4
(
192
,
168
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
16
,
32
)},
// 192.168.0.0/16 (私有)
{
IP
:
net
.
IPv4
(
198
,
18
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
15
,
32
)},
// 198.18.0.0/15 (基准测试)
{
IP
:
net
.
IPv4
(
198
,
51
,
100
,
0
),
Mask
:
net
.
CIDRMask
(
24
,
32
)},
// 198.51.100.0/24 (TEST-NET-2)
{
IP
:
net
.
IPv4
(
203
,
0
,
113
,
0
),
Mask
:
net
.
CIDRMask
(
24
,
32
)},
// 203.0.113.0/24 (TEST-NET-3)
{
IP
:
net
.
IPv4
(
224
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
4
,
32
)},
// 224.0.0.0/4 (组播)
{
IP
:
net
.
IPv4
(
240
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
4
,
32
)},
// 240.0.0.0/4 (保留)
{
IP
:
net
.
IPv4
(
255
,
255
,
255
,
255
),
Mask
:
net
.
CIDRMask
(
32
,
32
)},
// 255.255.255.255/32 (受限广播)
}
// privateIPv6Nets IPv6 私有/保留/特殊用途网段
// 参考 IANA IPv6 Special-Purpose Address Registry
// https://www.iana.org/assignments/iana-ipv6-special-registry/
var
privateIPv6Nets
=
func
()
[]
net
.
IPNet
{
cidrs
:=
[]
string
{
"::/128"
,
// 未指定地址
"::1/128"
,
// 回环
"::ffff:0:0/96"
,
// IPv4-mapped
"64:ff9b::/96"
,
// IPv4/IPv6 translation
"100::/64"
,
// Discard-Only
"2001::/23"
,
// IETF Protocol Assignments
"2001:db8::/32"
,
// 文档
"fc00::/7"
,
// Unique Local Address (ULA)
"fe80::/10"
,
// 链路本地
"ff00::/8"
,
// 组播
}
nets
:=
make
([]
net
.
IPNet
,
0
,
len
(
cidrs
))
for
_
,
c
:=
range
cidrs
{
if
_
,
n
,
err
:=
net
.
ParseCIDR
(
c
);
err
==
nil
&&
n
!=
nil
{
nets
=
append
(
nets
,
*
n
)
}
}
return
nets
}()
// isPrivateIP 检查IP是否为私有/保留/特殊用途地址
func
isPrivateIP
(
ip
net
.
IP
)
bool
{
func
isPrivateIP
(
ip
net
.
IP
)
bool
{
if
ip
==
nil
{
return
true
}
// 未指定地址 (0.0.0.0, ::)
if
ip
.
IsUnspecified
()
{
return
true
}
// 回环、链路本地 (unicast/multicast)
if
ip
.
IsLoopback
()
||
ip
.
IsLinkLocalUnicast
()
||
ip
.
IsLinkLocalMulticast
()
{
if
ip
.
IsLoopback
()
||
ip
.
IsLinkLocalUnicast
()
||
ip
.
IsLinkLocalMulticast
()
{
return
true
return
true
}
}
// 接口本地组播 (IPv6 ff01::/16 等)
// 检查私有网段
if
ip
.
IsInterfaceLocalMulticast
()
{
private
:=
[]
net
.
IPNet
{
return
true
{
IP
:
net
.
IPv4
(
10
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
8
,
32
)},
// 10.0.0.0/8
{
IP
:
net
.
IPv4
(
172
,
16
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
12
,
32
)},
// 172.16.0.0/12
{
IP
:
net
.
IPv4
(
192
,
168
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
16
,
32
)},
// 192.168.0.0/16
{
IP
:
net
.
IPv4
(
127
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
8
,
32
)},
// 127.0.0.0/8
{
IP
:
net
.
IPv4
(
169
,
254
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
16
,
32
)},
// 169.254.0.0/16 (链路本地)
{
IP
:
net
.
IPv4
(
224
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
4
,
32
)},
// 224.0.0.0/4 (组播)
{
IP
:
net
.
IPv4
(
240
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
4
,
32
)},
// 240.0.0.0/4 (保留)
}
}
for
_
,
privateNet
:=
range
private
{
if
v4
:=
ip
.
To4
();
v4
!=
nil
{
if
privateNet
.
Contains
(
ip
)
{
for
_
,
privateNet
:=
range
privateIPv4Nets
{
return
true
if
privateNet
.
Contains
(
v4
)
{
return
true
}
}
}
return
false
}
}
// 检查IPv6私有地址
// IPv6 检查
if
ip
.
To4
()
==
nil
{
for
_
,
privateNet
:=
range
privateIPv6Nets
{
// IPv6 loopback
if
privateNet
.
Contains
(
ip
)
{
if
ip
.
Equal
(
net
.
IPv6loopback
)
{
return
true
}
// IPv6 link-local
if
strings
.
HasPrefix
(
ip
.
String
(),
"fe80:"
)
{
return
true
}
// IPv6 unique local
if
strings
.
HasPrefix
(
ip
.
String
(),
"fc"
)
||
strings
.
HasPrefix
(
ip
.
String
(),
"fd"
)
{
return
true
return
true
}
}
}
}
// 兜底: Go 标准库识别的其他私有地址
if
ip
.
IsPrivate
()
{
return
true
}
return
false
return
false
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment