SSRF服务端请求伪造漏洞与防护
字数 860 2025-11-03 00:19:05
SSRF服务端请求伪造漏洞与防护
题目描述
SSRF(Server-Side Request Forgery)是一种由攻击者构造恶意请求,诱使服务端向内部或外部系统发起非预期网络请求的安全漏洞。与CSRF攻击客户端不同,SSRF利用的是服务端对用户请求的信任。典型场景包括:服务器无防护地代理用户请求资源、解析URL时未校验目标地址、或访问内部元数据服务(如云环境的169.254.169.254)。
漏洞原理与危害
-
攻击路径:
- 用户提交URL(如图片加载、网页抓取功能)→ 服务端直接请求该URL → 攻击者伪造指向内网或本地服务的地址 → 服务端代发请求并返回结果。
示例请求:
POST /api/download_image HTTP/1.1 Content-Type: application/json {"url": "file:///etc/passwd"} # 尝试读取服务器本地文件 - 用户提交URL(如图片加载、网页抓取功能)→ 服务端直接请求该URL → 攻击者伪造指向内网或本地服务的地址 → 服务端代发请求并返回结果。
-
核心危害:
- 内网渗透:访问防火墙保护的内部系统(如数据库管理界面)。
- 敏感信息泄露:通过云元数据服务获取实例密钥、配置信息。
- 端口扫描:利用服务端响应时间差异探测内网端口开放情况。
漏洞复现与利用步骤
假设存在一个在线工具,允许用户输入URL让服务器获取远程图片:
-
正常请求:
{"url": "https://example.com/image.jpg"}服务器下载该图片并返回成功。
-
探测内网服务:
攻击者尝试访问内网IP段:{"url": "http://192.168.1.1:8080/admin"}若响应包含登录页面HTML,则确认内网存在管理后台。
-
利用云元数据服务(以AWS为例):
{"url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}服务器会返回临时访问密钥,导致云平台权限泄露。
-
协议滥用:
利用file://协议读取本地文件,或dict://协议与Redis等服务交互:{"url": "file:///etc/passwd"} {"url": "dict://127.0.0.1:6379/info"} # 获取Redis信息
防护方案
-
输入校验与过滤:
- 白名单校验域名和协议(仅允许
https://example.com等可信域名)。 - 禁止访问内网IP段(如
10.0.0.0/8)、回环地址(127.0.0.1)。
- 白名单校验域名和协议(仅允许
-
网络层隔离:
- 服务器出站流量限制:禁止访问云元数据IP、内网网段。
- 使用中间代理并设置目标地址规则。
-
权限最小化:
- 运行服务的账户权限应受限,避免高权限读取系统文件。
-
响应内容检查:
- 服务器获取远程内容后,校验返回数据的类型(如图片需验证文件头),避免直接返回敏感信息。
案例:防护代码示例(Node.js)
const url = require('url');
const allowedDomains = ['cdn.example.com']; // 白名单域名
function validateURL(inputURL) {
const parsed = url.parse(inputURL);
// 协议限制:仅允许HTTP/HTTPS
if (!['http:', 'https:'].includes(parsed.protocol)) {
throw new Error('协议不被允许');
}
// 域名白名单校验
if (!allowedDomains.includes(parsed.hostname)) {
throw new Error('域名不在白名单内');
}
// 禁止内网IP访问
const ip = parsed.hostname;
if (isInternalIP(ip)) {
throw new Error('禁止访问内网地址');
}
return true;
}
function isInternalIP(ip) {
const ranges = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'];
return ranges.some(range => ipInRange(ip, range));
}