This commit is contained in:
2026-05-24 11:42:38 +08:00
commit 30d312ac35
521 changed files with 146481 additions and 0 deletions
@@ -0,0 +1,217 @@
---
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<br/>穿越 NAT 发现自己对外暴露的地址/port"] --> ICE
TURN["TURN<br/>中继服务器转发流量<br/>兜底方案"] --> ICE
ICE["ICE 框架<br/>按优先级尝试: 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 校验判断