72 lines
1.1 KiB
Go
72 lines
1.1 KiB
Go
package security
|
||
|
||
import (
|
||
"net"
|
||
"net/url"
|
||
|
||
"proxyrotator/internal/model"
|
||
)
|
||
|
||
// ValidateTestURL 校验测试目标 URL,防止 SSRF
|
||
func ValidateTestURL(rawURL string) error {
|
||
u, err := url.Parse(rawURL)
|
||
if err != nil {
|
||
return model.ErrInvalidURL
|
||
}
|
||
|
||
// 只允许 http/https
|
||
if u.Scheme != "http" && u.Scheme != "https" {
|
||
return model.ErrUnsafeScheme
|
||
}
|
||
|
||
// 解析主机名
|
||
host := u.Hostname()
|
||
if host == "" {
|
||
return model.ErrInvalidURL
|
||
}
|
||
|
||
// 解析 IP 地址
|
||
ips, err := net.LookupIP(host)
|
||
if err != nil {
|
||
return model.ErrInvalidURL
|
||
}
|
||
|
||
// 检查是否为私网 IP
|
||
for _, ip := range ips {
|
||
if IsPrivateIP(ip) {
|
||
return model.ErrPrivateIP
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// IsPrivateIP 判断是否为私网 IP
|
||
func IsPrivateIP(ip net.IP) bool {
|
||
if ip == nil {
|
||
return false
|
||
}
|
||
|
||
// 回环地址
|
||
if ip.IsLoopback() {
|
||
return true
|
||
}
|
||
|
||
// 链路本地地址
|
||
if ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
|
||
return true
|
||
}
|
||
|
||
// 私有地址
|
||
if ip.IsPrivate() {
|
||
return true
|
||
}
|
||
|
||
// 未指定地址
|
||
if ip.IsUnspecified() {
|
||
return true
|
||
}
|
||
|
||
return false
|
||
}
|