发布于15小时前15小时 问题背景在一次授权的企业 Web 应用测试中,测试目标为外网入口 URL 下载图片。初步测试发现该功能疑似存在服务端请求伪造(SSRF)。问题不在于“能否访问某个地址”本身,而在于请求是否突破了网络分区和身份边界:外部请求是否能到达仅供内网使用的接口,内网接口是否错误地信任来源地址,以及整个过程能否在日志中还原。以下验证均使用客户提供的测试域名、测试账户和专用 Canary 地址,不访问云平台元数据、生产凭据或其他租户数据。一、问题定位:先证明请求确实由服务端发出不要直接使用内网地址作为第一步验证。先准备一个由测试方控制的 HTTPS Canary 地址,例如 204,并记录请求时间、来源 IP、User-Agent 和自定义标识。在应用中提交该地址后,检查 Canary 侧是否收到请求。如果收到请求,再通过应用日志中的请求 ID 与 Canary 日志进行关联。这样可以区分浏览器直连、前端预览和后端实际下载三种情况。# 仅用于验证测试应用是否向授权 Canary 发起后端请求 curl -sk -X POST ' \ -H 'Authorization: Bearer <测试令牌>' \ -H 'Content-Type: application/json' \ -H 'X-Test-Case: ssrf-boundary-001' \ --data '{"url":" \ -D /tmp/ssrf-response.headers # 查看响应状态和请求关联信息 cat /tmp/ssrf-response.headers如果 Canary 收到请求,说明服务端存在可控的出站请求能力。此时应记录以下证据:请求时间、测试账户、业务接口、目标 URL、应用返回码、Canary 侧来源地址,以及应用日志中的 trace ID。二、验证内网边界:只访问专用测试服务在客户提供的测试网段中部署一个无敏感数据的 HTTP 测试服务,例如 10.20.30.40:8080,只返回固定文本 internal-canary。不要扫描整个网段,也不要尝试访问数据库、缓存、云元数据或管理面板。使用 SSRF 功能请求该测试服务,并将结果与直接从测试机访问的结果对比:# 直接访问仅用于确认测试服务可用,不代表应用所在网络可达 curl --max-time 3 -i # 通过业务接口请求测试服务,具体参数以实际接口为准 curl -sk -X POST ' \ -H 'Authorization: Bearer <测试令牌>' \ -H 'Content-Type: application/json' \ --data '{"url":" internal-canary,并且测试服务日志记录到请求,说明应用运行环境可以访问该内网地址。应用返回超时,但测试服务没有日志,通常是路由、防火墙或代理策略阻断,不能据此认定不存在 SSRF。应用返回内部错误、响应头或连接异常信息,说明错误处理可能泄露内部网络细节,需要单独记录。测试服务看到的来源地址属于应用服务器或其出口代理,而不是测试者公网地址,才能证明请求由服务端发起。三、权限边界分析:确认内网服务是否错误信任来源如果内网测试服务存在“仅允许内网访问”的接口,应将其替换为专用的无敏感测试接口,返回固定的版本标识和访问来源,不返回账号、令牌或配置内容。重点观察访问控制是否只依赖源 IP。例如测试服务可以记录以下信息:# 测试服务访问日志示例,实际字段由服务端配置决定 2025-02-18T10:21:03Z src=10.20.10.15 method=GET path=/health \ status=200 user_agent="portal-fetcher/1.4" \ request_id=ssrf-boundary-001若应用服务器能够仅凭网络位置访问内部管理接口,说明“网络可达性”被错误地当成了“身份认证”。这类问题通常比单纯的 SSRF 更严重,因为攻击链可能从外部 URL 获取能力,进一步触达内部控制面。验证权限边界时,应至少回答三个问题:内网服务是否要求独立认证,而不是仅检查来源 IP?应用服务账号是否拥有超出业务所需的网络访问权限?内部接口返回的数据是否包含令牌、连接串、调试信息或其他可继续利用的材料?在授权测试中,发现敏感字段后应立即停止扩大读取范围,只保存字段名称、脱敏后的样例和响应长度,避免采集真实凭据。四、日志排查:把一次请求串成完整链路建议以同一个测试标识贯穿入口网关、应用、出站代理、内网测试服务和主机审计日志。若应用没有透传测试标识,可使用测试时间窗口、源端口、用户账号和接口路径进行交叉关联。Nginx 或网关侧重点查看请求是否进入业务接口:# 按测试时间和接口筛选网关日志 awk '$7 ~ /\/api\/avatar\/fetch/ {print}' /var/log/nginx/access.log | tail -n 50 # 查看应用服务在测试时间窗口内的日志 journalctl -u portal --since '2025-02-18 10:20:00' --until '2025-02-18 10:25:00' \ | grep -E 'ssrf-boundary-001|avatar/fetch|outbound'如果环境使用 Linux auditd,可以对应用配置目录和网络工具调用进行审计,但不要在生产环境临时扩大规则导致日志暴增。一个较窄的排查规则示例如下:# 仅在授权测试窗口内使用,观察应用是否读取配置文件 auditctl -w /opt/portal/config -p r -k portal-config-read # 测试结束后移除临时规则 augenrules --load ausearch -k portal-config-read -ts recent -i实际分析时需要注意:容器环境下应用日志可能写入 stdout,由容器运行时或日志代理统一采集;宿主机的 journalctl 不一定能直接看到容器内请求。应同时检查容器编排平台的日志、出口代理日志和网络流量审计记录。五、常见误判与排查顺序把浏览器请求误认为 SSRF:检查 Canary 侧来源地址和 User-Agent,确认请求来自应用运行环境。只看 HTTP 状态码:应用可能将内部响应统一转换为 200 或 500,应结合测试服务日志判断是否真正建立连接。忽略 DNS 解析:应用可能先由本地 DNS 解析,再通过代理出站。应记录解析结果和最终连接地址,避免仅按 URL 字符串做黑名单。只在网关层修复:如果应用容器、任务队列或其他微服务仍可任意出站,攻击面并未真正收敛。为了证明影响而读取真实秘密:验证到“可访问敏感接口”即可停止,使用固定测试数据证明权限边界,不应继续提取凭据。六、修复建议1. 在应用层实施严格 URL 校验不要只过滤 127.0.0.1 或字符串形式的内网地址。应采用允许列表,限制协议为 HTTPS,解析域名后对所有 A、AAAA 记录进行 IP 分类,并在建立连接前后都校验最终地址,防止 DNS rebinding。仅允许业务必需的域名和端口。拒绝回环、链路本地、私有地址、保留地址以及 IPv4-mapped IPv6 地址。禁用不必要的重定向,或对每次重定向重新执行完整校验。限制响应大小、连接时间、跳转次数和下载类型。错误信息不要返回内部地址、解析结果或代理细节。2. 在网络层建立默认拒绝策略应用服务器或容器的出站访问应默认拒绝,只允许访问明确列出的外部服务。内网管理接口不应仅靠源 IP 认证,至少需要独立身份认证、细粒度授权和必要的 mTLS。应用账号不应拥有访问数据库管理端口、云控制面或主机管理接口的权限。3. 关闭不必要的代理和调试能力检查环境变量 HTTP_PROXY、HTTPS_PROXY、NO_PROXY,确认应用不会通过开放代理绕过网络策略。生产环境关闭调试端点、内部健康检查中的敏感字段和详细异常堆栈。4. 补充可检测性应用应记录请求用户、目标域名、解析结果、最终连接地址、响应状态、耗时和拒绝原因,但不要记录完整的 Authorization 头或 URL 中的敏感参数。对连续请求私有地址、端口探测式失败和异常重定向建立告警。七、报告结论建议报告中应把“漏洞事实”和“潜在影响”分开书写。例如:事实:外部测试账户可调用头像获取接口,服务端向授权 Canary 发起请求,并可访问测试网段中的内部 Canary 服务。边界问题:内部服务仅依赖来源网段进行访问控制,未要求独立认证。未验证事项:未访问云元数据、生产管理接口、真实凭据和其他租户数据。修复重点:应用层 URL 允许列表、解析后 IP 校验、出站网络默认拒绝、内部服务独立认证,以及入口和出站日志关联。总结授权渗透中的 SSRF 验证不应停留在“能访问内网”这一结论。更有价值的问答式排查是:请求是否由服务端发出、实际到达了哪一层网络、内网服务依赖什么身份判断、应用账号拥有怎样的权限,以及整个链路能否被日志完整还原。使用专用 Canary、最小化访问范围和可关联的测试标识,可以在不读取真实敏感数据的前提下证明风险,并为修复提供明确依据。 服务器、云资产与权限边界梳理示意 网络请求、日志与边界流量分析示意
14小时前14小时 这类验证最好把“能发起请求”和“获得内网权限”拆开,不要直接拿真实管理接口做探测。建议在授权范围内放一个受控的内网 canary 服务,用唯一标识完成证据闭环。 验证网络可达性:让疑似 SSRF 点请求 canary 的高位端口,例如 /ssrf-check/<UUID>。服务端记录源地址、Host、请求方法、请求头和 TLS 客户端身份。收到请求只能证明该应用工作负载可达该网段,不能直接等同于有业务权限。 验证权限边界:在 canary 上分别设置匿名返回 401、指定服务身份返回 200 的路径,观察 SSRF 请求是否自动携带代理认证头、Cookie、mTLS 证书或云身份。测试使用无副作用的 GET/HEAD,不要访问真实管理、数据库或元数据接口。 覆盖常见绕过面:至少检查 HTTP/HTTPS 协议限制、IPv4/IPv6、重定向后的再次校验、DNS 多记录、短 TTL,以及 URL 中 userinfo、尾点域名和大小写归一化。重定向目标和每一跳解析结果都必须重新执行策略。 canary 节点可同时留应用日志和抓包,避免只依赖一侧证据: TOKEN="$(date +%s)-ssrf-test" sudo tcpdump -ni any 'tcp port 18080' -w "/tmp/${TOKEN}.pcap" # nginx 可单独配置日志格式 log_format ssrf '$time_iso8601 token=$http_x_test_id ' 'src=$remote_addr host=$host method=$request_method ' 'uri=$request_uri status=$status ' 'xff="$http_x_forwarded_for"'; access_log /var/log/nginx/ssrf-canary.log ssrf; 定位日志时按同一个 UUID 和时间窗口串联以下几层: 入口网关/WAF:确认触发参数、调用者和原始 request ID。 业务应用:记录规范化后的目标域名、解析出的全部 A/AAAA 地址、重定向链和最终错误类型。不要记录 URL 中可能存在的凭据。 出口代理或 Service Mesh:重点看实际连接的 upstream_host,因为它比原始 URL 更能说明请求最终去了哪里。 DNS、VPC Flow Log、主机防火墙:用于确认解析结果、真实目标 IP、端口及 ACCEPT/REJECT。 # systemd 服务 journalctl -u target-app --since "20 minutes ago" | grep -F "$TOKEN" # Kubernetes kubectl logs -n app deploy/target-app --all-containers --since=20m | grep -F "$TOKEN" # 受控目标 grep -F "$TOKEN" /var/log/nginx/ssrf-canary.log 云元数据地址不建议通过实际读取凭据来证明。应通过出口拒绝日志确认其不可达,并同步检查元数据服务配置,例如 AWS 强制 IMDSv2、限制 hop limit;即使应用层校验失效,也不应允许工作负载直接读取不需要的实例身份。 修复上不要只做字符串黑名单。比较稳妥的是“集中 URL 校验 + 固定出口代理 + 网络层默认拒绝”: from urllib.parse import urlsplit import socket import ipaddress def validate_target(raw_url, allowed_hosts): u = urlsplit(raw_url) if u.scheme not in {"http", "https"}: raise ValueError("unsupported scheme") if u.username is not None or u.password is not None: raise ValueError("userinfo is not allowed") if not u.hostname: raise ValueError("missing host") host = u.hostname.rstrip(".").lower() if host not in allowed_hosts: raise ValueError("host is not allowlisted") infos = socket.getaddrinfo(host, u.port or (443 if u.scheme == "https" else 80)) addresses = {ipaddress.ip_address(item[4][0]) for item in infos} # 任意一个解析结果不满足策略都拒绝,避免客户端随机选到内网地址 if not addresses or any(not addr.is_global for addr in addresses): raise ValueError("non-public address rejected") return u, addresses 上面的校验只能作为前置策略,不能单独解决 DNS rebinding/TOCTOU。实际连接时应固定到已校验的 IP,同时保留正确的 HTTP Host 和 TLS SNI;每次重定向重新解析并校验。更推荐让业务只能访问受控出口代理,由代理执行域名白名单和最终目标 IP 校验,并在网络策略中禁止业务 Pod 直接访问 RFC1918、loopback、link-local、IPv6 ULA 和云元数据网段。 最终报告里建议分别写清:请求是否被应用接受、是否到达内网、使用了什么工作负载身份、服务端返回 401/403/200,以及对应的应用日志、出口日志和流日志。这样能准确界定是单纯 SSRF、内网横向可达,还是已经跨越了身份授权边界。
创建帐户或登录后发表意见