Init
This commit is contained in:
@@ -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 校验判断
|
||||
Reference in New Issue
Block a user