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
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
68 additions
and
24 deletions
+68
-24
common/ssrf_protection.go
+68
-24
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 私有/保留/特殊用途网段
func
isPrivateIP
(
ip
net
.
IP
)
bool
{
// 参考 IANA IPv4 Special-Purpose Address Registry
if
ip
.
IsLoopback
()
||
ip
.
IsLinkLocalUnicast
()
||
ip
.
IsLinkLocalMulticast
()
{
// https://www.iana.org/assignments/iana-ipv4-special-registry/
return
true
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)
private
:=
[]
net
.
IPNet
{
{
IP
:
net
.
IPv4
(
127
,
0
,
0
,
0
),
Mask
:
net
.
CIDRMask
(
8
,
32
)},
// 127.0.0.0/8 (回环)
{
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
(
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
(
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
(
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 (受限广播)
}
for
_
,
privateNet
:=
range
private
{
// privateIPv6Nets IPv6 私有/保留/特殊用途网段
if
privateNet
.
Contains
(
ip
)
{
// 参考 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
{
if
ip
==
nil
{
return
true
return
true
}
}
// 未指定地址 (0.0.0.0, ::)
if
ip
.
IsUnspecified
()
{
return
true
}
}
// 回环、链路本地 (unicast/multicast)
// 检查IPv6私有地址
if
ip
.
IsLoopback
()
||
ip
.
IsLinkLocalUnicast
()
||
ip
.
IsLinkLocalMulticast
()
{
if
ip
.
To4
()
==
nil
{
// IPv6 loopback
if
ip
.
Equal
(
net
.
IPv6loopback
)
{
return
true
return
true
}
}
// IPv6 link-local
// 接口本地组播 (IPv6 ff01::/16 等)
if
strings
.
HasPrefix
(
ip
.
String
(),
"fe80:"
)
{
if
ip
.
IsInterfaceLocalMulticast
(
)
{
return
true
return
true
}
}
// IPv6 unique local
if
strings
.
HasPrefix
(
ip
.
String
(),
"fc"
)
||
strings
.
HasPrefix
(
ip
.
String
(),
"fd"
)
{
if
v4
:=
ip
.
To4
();
v4
!=
nil
{
for
_
,
privateNet
:=
range
privateIPv4Nets
{
if
privateNet
.
Contains
(
v4
)
{
return
true
return
true
}
}
}
}
return
false
}
// IPv6 检查
for
_
,
privateNet
:=
range
privateIPv6Nets
{
if
privateNet
.
Contains
(
ip
)
{
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