--- tags: [计算机网络, SSRF, DNS安全, DNSSEC, DoH, NAT穿透] create time: 2026-05-18 05:00 --- # SSRF 与 DNS 安全 ## 概述 SSRF(服务端请求伪造)是近年来增长最快的 Web 漏洞之一,它利用的是"服务器代替用户发起请求"的能力。DNS 层面则有从传统查询到 DoH/DoT 的安全演进。 ## SSRF(Server-Side Request Forgery) ### 什么是 SSRF? 当应用程序接受一个 URL 作为输入,并在服务端向该 URL 发起请求时,攻击者可以构造特殊 URL 让服务器访问**内部资源**(内网 API、元数据服务、数据库端口等)。 ### 典型攻击场景 ```go // ❌ 危险代码:用户控制 URL,服务器代替用户发起请求 func fetchImageHandler(w http.ResponseWriter, r *http.Request) { url := r.URL.Query().Get("url") // 用户可传入内网地址! resp, err := http.Get(url) // GET http://169.254.169.254/latest/meta-data/ if err != nil { http.Error(w, err.Error(), 500) return } defer resp.Body.Close() io.Copy(w, resp.Body) // AWS EC2 返回: access_key, secret_key, role... 💀 } ``` ### SSRF 常见探测目标 ``` 目标 说明 危害 ────────────────────── ─────────────────────── ──────────────────── 169.254.169.254 AWS/Azure/GCP 元数据 获取云实例凭证 10.0.0.x / 172.16.x.x 内网扫描 发现内网服务 file:///etc/passwd 文件读取协议 读取服务器敏感文件 gopher:// / dict:// Gopher/Dict 协议 利用回显放大攻击 docker.sock Docker Socket 远程执行容器命令 localhost:6379 Redis/Memcached 内网渗透跳板 ``` ### 安全的 SSRF 防御方案 ```go package main import ( "errors" "net" "net/http" "net/url" "time" ) var safeClient = &http.Client{ Timeout: 10 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error { return errors.New("no redirect") // 禁止重定向!攻击者可以用 302 绕校验 }, } // SafeFetch 安全地从一个 URL 获取内容 func SafeFetch(urlStr string) ([]byte, error) { parsed, err := url.Parse(urlStr) if err != nil { return nil, err } // 第一步:解析域名,拿到 IP ips, err := net.LookupIP(parsed.Host) if err != nil { return nil, err } // 第二步:检查所有可能的 IP(IPv4 + IPv6) for _, ip := range ips { if isUnsafeIP(ip) { return nil, errors.New("unsafe IP blocked: " + ip.String()) } } // 第三步:额外检查 Host 字段(防止 DNS rebinding 攻击) if hostIP := net.ParseIP(parsed.Host); hostIP != nil { if isUnsafeIP(hostIP) { return nil, errors.New("host IP unsafe: " + hostIP.String()) } } resp, err := safeClient.Get(urlStr) if err != nil { return nil, err } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) return body, nil } func isUnsafeIP(ip net.IP) bool { if ip.IsPrivate() || ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsUnspecified() { return true } // 额外检查:云元数据地址段 if ip.Equal(net.ParseIP("169.254.169.254")) { return true } return false } ``` ```go // Nginx 层面的 SSRF 防御(反向代理入口) location /api/fetch { # 禁止直接访问内网 internal; # 只允许内部 rewrite 访问 proxy_pass $arg_url; proxy_hide_header Access-Control-Allow-Origin; } ``` > [!warning] DNS Rebinding 攻击 > > 即使你检查了初始 IP,攻击者仍可以将 DNS TTL 设为极小值(如 0 秒),让你的代码先校验合法 IP,然后在第二次请求时 DNS 已返回内网 IP。 > **应对策略**:在整个请求生命周期中持续校验;使用白名单域名而非黑名单 IP;禁用重定向。 ## DNS 安全 ### DNSSEC —— 给 DNS 加上数字签名 ``` 传统 DNS(明文无签名): DNSSEC(带签名验证): Resolver → authoritative → answer Resolver → authoritative → answer + SIG Resolver 用 DNSKEY 验证签名 ✅ 如果签名不对 → 返回 SERVFAIL ❌ ``` ```bash # 检查某域名的 DNSSEC 状态 $ dig +dnssec example.com ;; flags: ad; AD 表示 Answer data verified by DNSSEC ✅ # 本地递归解析器配置(bind / unbound) # /etc/bind/named.conf dnssec-validation auto; # bind 自动下载根密钥 ``` ### DoH / DoT / DoQ —— 加密 DNS 查询 | 协议 | 载体 | 端口 | 特点 | |------|------|------|------| | **DNS over TLS (DoT)** | TCP + TLS | 853 | RFC 7858, 传输层加密 | | **DNS over HTTPS (DoH)** | HTTP/2 + TLS | 443 | RFC 8484, 伪装成 HTTPS 流量 | | **DNS over QUIC (DoQ)** | QUIC | 853 | 最新标准, 低延迟 + 抗干扰 | ```bash # curl 测试 DoH $ curl -v https://dns.google/resolve?name=example.com&type=A \ -H 'accept: application/dns-json' * TLS 1.3 connection using TLS_AES_256_GCM_SHA384 * DNS query goes over encrypted HTTPS channel ✅ # unbound 配置 DoT 递归 # /etc/unbound/unbound.conf.d/doth-forwarders.conf forward-zone: name: "." forward-ssl-upstream: yes forward-addr: 1.1.1.1@853 # Cloudflare DoT forward-addr: 8.8.8.8@853 # Google DoT ``` ### DHCP 安全注意事项 ``` DHCP DORA 四步本身是无认证的: Discover → Offer → Request → Acknowledge 风险: • Rogue DHCP Server:恶意 DHCP 分配错误的网关/DNS • DHCP Starvation:耗尽 DHCP 地址池 防御: • Switch 端口安全:DHCP Snooping • 802.1X 认证:未认证的端口不参与 DHCP • 静态绑定:关键设备用 static IP + DHCP Reservation ``` ## NAT 穿透技术补充 ```mermaid flowchart TD STUN["STUN
穿越 NAT 发现自己对外暴露的地址/port"] --> ICE TURN["TURN
中继服务器转发流量
兜底方案"] --> ICE ICE["ICE 框架
按优先级尝试: direct → STUN → TURN"] --> SUCCESS["✅ 建立 P2P 连接"] style STUN fill:#98FB98,color:#000 style TURN fill:#FFD700,color:#000 style SUCCESS fill:#DDA0DD,color:#000 ``` - **STUN**:客户端向 STUN 服务器发请求,拿到自己的公网 IP:Port。但对称型 NAT 下 STUN 失效。 - **TURN**:所有流量经中继服务器中转,兼容性最好但延迟最高。 - **ICE**:WebRTC 的标准框架,同时收集候选地址并按连通性排序。 ## 关联笔记 - [[hhs/NETWORK/NAT原理与应用]] — NAT 穿透技术(STUN/TURN/ICE)的详细原理 - [[hhs/NETWORK/DNS与DHCP与WebSocket]] — DNS 递归查询与 DoH/DoT 的完整实现 - [[hhs/NETWORK/04-寻址体系MAC-IPTPort]] — 私有 IP 地址范围用于 SSRF 校验判断