《白帽子讲 Web 安全》之服务端请求伪造(SSRF)深度剖析:从攻击到防御

引言

在当今复杂的网络环境中,Web 应用安全犹如一座时刻需要精心守护的堡垒。随着技术的不断演进,各类安全威胁层出不穷,其中服务端请求伪造(SSRF)正逐渐成为令开发者与安全从业者头疼的一大难题。吴翰清在《白帽子讲 Web 安全》中对 SSRF 进行了深入探讨,接下来让我们详细梳理这一安全隐患的相关知识。

SSRF 攻击简介

定义

服务端请求伪造(Server Side Request Forgery,SSRF)本质上是一种严重的 Web 应用漏洞。攻击者通过精心构造特定的参数值,诱使 Web 应用将外部输入参数当作 URL 来处理,进而驱使服务端去访问那些服务器程序原本预期之外的 URL。这些输入参数形式多样,既可以是不完整的 URL,也能是单纯的域名、IP 地址或者端口值等。

示例

以提供翻译服务的网站为例,正常情况下用户提交网页 URL 供网站进行翻译操作。但倘若该网站存在 SSRF 漏洞,攻击者便有机可乘。他们提交恶意 URL,网站服务器在毫无察觉的情况下,按照指令访问该恶意 URL,甚至可能因此访问到内网资源,导致敏感信息泄露等严重后果。比如攻击者提交 “http://192.168.1.100/internal_secret_file”,若服务器未做有效防范,就会尝试访问内网 IP 对应的敏感文件。

SSRF 漏洞成因

1.用户输入处理不当

许多 Web 应用在处理用户输入时过于草率。当使用用户输入来构造 HTTP 请求的 URL 时,却没有进行全面且严格的验证与过滤。像是未仔细检查 URL 所采用的协议是否合法,是常见的 HTTP/HTTPS,还是潜藏风险的 file、gopher 等协议;对域名的合法性以及端口值是否处于合理范围也未加以核实。以 Python 的 Flask 框架为例,如果代码编写如下:

from flask import Flask, requestapp = Flask(__name__)@app.route('/fetch')
def fetch():url = request.args.get('url')# 这里没有对url进行任何验证就直接使用response = requests.get(url)return response.text

如此一来,用户输入的任何 URL 都可能被服务器访问,极大地增加了 SSRF 风险。

2.使用未经验证的第三方库或框架

在开发过程中,不少开发者依赖各种第三方库或框架来加快开发进度。然而,部分未经充分安全验证的库或框架,在处理 URL 请求环节存在安全漏洞,极易被攻击者利用。例如某些老旧版本的 HTTP 请求库,在处理 URL 重定向等操作时,没有对目标 URL 进行严格检查,攻击者可借此构造恶意请求,突破应用的安全防线。

3.缺乏安全配置

服务器自身的配置若存在缺陷,同样会为 SSRF 攻击敞开大门。比如服务器未对可访问的 URL 范围做出明确限制,或者未严格检查请求来源,使得攻击者能够轻易绕过安全限制。以 Nginx 服务器为例,如果配置文件中没有设置合理的访问控制规则,像以下错误配置:

server {listen 80;server_name example.com;location / {proxy_pass $request_uri;# 这里没有对proxy_pass的目标进行任何限制}
}

攻击者就可以通过精心构造请求,让服务器访问任意他们指定的 URL。

SSRF 攻击进阶

1.攻击内网应用

攻击者一旦发现 Web 应用存在 SSRF 漏洞,便会将目标对准内网应用或服务。通过构造特殊的 URL,诱使服务器去访问内网的 Redis、MySQL 等数据库服务。

例如利用 file 协议,攻击者可以构造类似 “file:///etc/passwd” 的 URL,若服务器权限配置不当,就会读取服务器本地的敏感文件。

利用 gopher 协议攻击 Redis 服务时,攻击者构造的 URL 可以向 Redis 服务器发送恶意指令,如修改数据库内容、获取敏感数据等。假设 Redis 服务在内网 IP 为 192.168.1.101,端口为 6379,攻击者构造的 gopher URL 可能如下:

gopher://192.168.1.101:6379/_*3%0d%0a$3%0d%0aset%0d%0a$1%0d%0a1%0d%0a$4%0d%0amalic%0d%0a

这条 URL 会尝试在 Redis 中设置恶意数据。

2.端口扫描

端口扫描也是攻击者利用 SSRF 漏洞的常见手段。通过向不同的端口发送请求,并根据响应判断端口是否开放,攻击者能够探测内网的服务和端口信息。攻击者可以编写脚本,利用 SSRF 漏洞构造一系列请求来扫描内网端口。例如使用 Python 编写一个简单的端口扫描脚本,结合 SSRF 漏洞向不同端口发送请求:

import requestsdef scan_port(url, port):target_url = f"{url}:{port}"try:response = requests.get(target_url)if response.status_code == 200:print(f"端口 {port} 开放")except requests.RequestException:passbase_url = "http://vulnerable_server/ssrf_endpoint?url="
for port in range(1, 1025):scan_port(base_url, port)

通过这种方式,攻击者可以为后续更深入的攻击做准备。

3.攻击非 Web 应用

SSRF 的攻击范围并不局限于 Web 应用,基于网络协议的其他服务,如 FTP、SMTP 等同样可能成为受害者。攻击者可以构造符合相应协议的 URL,借助 SSRF 漏洞与这些服务进行交互并执行恶意操作。例如构造一个针对 FTP 服务的 URL“ftp://attacker_server:21”,如果服务器对该 URL 请求未做限制,攻击者可能通过 FTP 服务上传恶意文件、获取敏感信息等。

SSRF 绕过技巧

1.绕过限制访问内网

为突破服务器对 URL 的限制从而访问内网资源,攻击者想出了多种特殊方法。DNS 重绑定技术是其中之一,攻击者通过控制 DNS 服务器,使域名在不同时间解析为不同 IP 地址。先让域名解析为外网可访问的 IP 地址,绕过服务器对访问内网 IP 的限制;在获取服务器连接后,再将域名解析为内网 IP 地址,从而实现对内网资源的访问。另外,攻击者还会使用特殊的 URL 编码和变形方式绕过过滤。例如将 “.” 编码为 “%2e”,将 “/” 编码为 “%2f” 等,以此绕过服务器对 URL 格式的简单过滤规则。

2.利用协议特性

不同的网络协议具有各自独特的特性,攻击者善于利用这些特性来绕过安全检测。以 HTTP 协议中的 30x 重定向为例,攻击者可以构造一个包含重定向指令的 URL,将服务器的请求重定向到内网地址。假设攻击者控制了一个恶意网站 “evil.com”,他们构造的 URL 可能是 “http://vulnerable_server/ssrf_endpoint?url=http://evil.com/redirect?target=http://192.168.1.100”,当服务器访问evil.com时,evil.com返回 302 重定向指令,将服务器请求重定向到内网 IP 地址 192.168.1.100,从而绕过服务器原本对直接访问内网地址的限制。

SSRF 防御方案

1.使用 URL 黑名单或白名单

黑名单

采用黑名单机制,即限制访问特定的 URL。然而,这种方式存在较大局限性,因为难以穷举所有危险的 URL,而且攻击者总能通过各种手段绕过黑名单限制,所以实际安全性较低。例如攻击者可以通过对危险 URL 进行变形、编码等方式,使其不在黑名单范围内。

白名单

相较而言,白名单机制更为可靠。它只允许访问特定的、经过严格验证的 URL。在实际应用中,明确指定允许访问的域名或 IP 地址范围是关键。例如在 Java 的 Spring 框架中,可以通过配置文件设置允许访问的 URL 白名单:

security.ssrf.whitelist=example.com,192.168.1.0/24

这样服务器只会访问白名单内的 URL,大大降低了 SSRF 攻击风险。

2.验证输入的 URL

对用户输入的 URL 进行严格验证是防御 SSRF 的重要一环。需要检查 URL 所采用的协议,只允许安全的协议,如 HTTP 或 HTTPS 协议,禁止 file、gopher 等可能被用于恶意攻击的协议。同时,对域名和 IP 地址的合法性也要进行核实。例如使用 Python 的urllib.parse库验证 URL:

from urllib.parse import urlparsedef validate_url(url):result = urlparse(url)if result.scheme not in ['http', 'https']:return Falsetry:# 验证域名或IP地址的合法性socket.gethostbyname(result.netloc.split(':')[0])return Trueexcept socket.gaierror:return False

3.限制请求的端口和协议

明确限制服务器可以访问的端口和协议,是减少攻击面的有效手段。禁止服务器访问不必要的端口,如一些常见的敏感端口,像 Redis 的 6379 端口MySQL 的 3306 端口等。同时,只允许使用必要的协议,避免启用可能被攻击者利用的协议。例如在服务器配置文件中设置只允许 HTTP 和 HTTPS 协议访问特定端口:

server {listen 80;server_name example.com;location / {proxy_pass http://backend_server;proxy_http_version 1.1;proxy_set_header Connection "";# 限制只允许HTTP和HTTPS协议if ($scheme!~ ^(http|https)$) {return 403;}# 限制只允许访问特定端口,如80和443if ($server_port!~ ^(80|443)$) {return 403;}}
}

4.使用 DNS 解析控制

对 URL 中的域名进行 DNS 解析,并检查解析后的 IP 地址是否合法,能够有效防止通过 DNS 重绑定等技术绕过限制。在服务器端获取 URL 中的域名后,先进行 DNS 解析,然后对比解析得到的 IP 地址是否在允许范围内。例如在 Node.js 中可以使用dns模块进行 DNS 解析验证:

const dns = require('dns');
const url = require('url');function validateUrlWithDns(urlStr) {const parsedUrl = url.parse(urlStr);return new Promise((resolve, reject) => {dns.lookup(parsedUrl.hostname, (err, address) => {if (err) {reject(err);} else {// 假设允许的IP范围是192.168.1.0/24const allowedRange = '192.168.1.0/24';if (isInRange(address, allowedRange)) {resolve(true);} else {reject(new Error('IP地址不在允许范围内'));}}});});
}function isInRange(ip, range) {const [start, end] = range.split('/')[1] === '32'? [ip, ip] : getRange(range);return ip >= start && ip <= end;
}function getRange(cidr) {const parts = cidr.split('/');const ip = parts[0].split('.').reduce((acc, part) => acc * 256 + parseInt(part, 10), 0);const bits = parseInt(parts[1], 10);const mask = (0xffffffff << (32 - bits)) >>> 0;const start = ip & mask;const end = start | ~mask;return [start, end];
}

5.记录和监控

记录所有的请求和响应,对防御 SSRF 至关重要。通过详细记录,便于及时发现异常请求。同时,对服务器的网络访问进行实时监控,一旦察觉到可疑的 SSRF 攻击行为,能够迅速采取措施。例如使用日志管理工具,如 ELK(Elasticsearch、Logstash、Kibana)组合,将服务器的请求和响应日志收集到 Elasticsearch 中,通过 Logstash 进行日志处理和过滤,再利用 Kibana 进行可视化展示和分析。一旦发现大量指向内网 IP 的请求或者异常的 URL 请求,安全人员可以及时介入调查并采取相应防御措施。

小结

服务端请求伪造(SSRF)作为近年来日益猖獗的 Web 安全风险,给 Web 应用的安全带来了巨大挑战。攻击者凭借这一漏洞,能够肆意访问内网资源、进行端口扫描等恶意操作,严重威胁数据安全与系统稳定。为有效防御 SSRF,我们需综合运用多种策略。

输入验证层面,严格把关用户输入的 URL,确保其合法性;采用白名单机制,精准限定服务器可访问的 URL 范围;

在网络层面,限制请求的协议和端口,减少攻击面;借助 DNS 解析控制,防范 DNS 重绑定等绕过手段;同时,强化监控与日志记录,以便及时察觉并处置潜在攻击。只有全方位、多层次地构建防御体系,持续关注安全动态,不断优化防御策略,才能在这场与 SSRF 的对抗中,守护好 Web 应用的安全,为用户营造可靠的网络环境。喜欢就点点赞和关注评论一起进步呗

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/42327.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pandas的轴,axis=0,axis=1

八. Pandas的轴 axis0代表跨行&#xff08;down)&#xff0c;而axis1代表跨列&#xff08;across) 使用0值表示沿着每一列或行标签\索引值向下执行方法使用1值表示沿着每一行或者列标签模向执行对应的方法 下图代表在DataFrame当中axis为0和1时分别代表的含义: axis参数作用…

matplotlib学习

开始学习Python数据可视化 一.基础绘图函数 1.创建画布与坐标轴 import matplotlib.pyplot as plt# 创建画布和坐标轴 fig, ax plt.subplots() # 默认1行1列&#xff0c;返回Figure对象和Axes对象 2.绘制线图 x [1, 2, 3, 4] y [10, 20, 15, 25]# 绘制线图 ax.plot(x,…

系统架构设计前的多角度思考

首先&#xff0c;从需求分析入手&#xff0c;不仅关注当前功能&#xff0c;还要考虑业务未来的扩展方向。比如数据量预估增长多少&#xff1f;这些都是影响架构的重要因素。 然后是架构设计原则&#xff0c;比如分层设计、模块化、高内聚低耦合等。比如如何划分服务边界&#x…

leetcode230.二叉搜索树中第k小的元素

中序遍历&#xff0c;第k次出现的数值就是结果 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left…

运筹说 第134期 | 矩阵对策的解法

上一期我们了解了矩阵对策的基本理论&#xff0c;包含矩阵对策的纯策略、矩阵对策的混合策略和矩阵对策的基本定理。 接下来小编将为大家介绍矩阵对策的解法&#xff0c;包括图解法、方程组法和线性规划法三种经典方法。 01 图解法 本节首先介绍矩阵对策的图解法&#xff0c;…

Python贝叶斯分层模型专题|对环境健康、医学心梗患者、体育赛事数据空间异质性实证分析合集|附数据代码

全文链接&#xff1a;https://tecdat.cn/?p41267 在大数据时代&#xff0c;多水平数据结构广泛存在于环境健康、医学研究和体育赛事等领域。本专题合集聚焦贝叶斯分层模型&#xff08;Hierarchical Bayesian Model&#xff09;的创新应用&#xff0c;通过氡气污染数据与 季后…

NOI2015提高组.子串

题目 520. 子串 思路 设计状态表示 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示 a a a的前 i i i个字符, b b b的前 j j j个字符, 并且已经分割了 k k k个子串的所有方案, 将状态划分为包含第 i i i个字符和不包含第 i i i个字符, 不包含第 i i i个字符的状态是 f [ i…

医疗智能体通信整合-大模型训练中沟通优化策略研究

一、引言:医疗模型训练的沟通困境 1.1 医疗 AI 发展背景 在数智化浪潮的推动下,医疗 AI 正以前所未有的速度融入现代医疗体系。从智能影像诊断助力医生精准识别病灶,到基于大数据分析的个性化药物研发,医疗 AI 在提升医疗效率、改善医疗质量方面展现出巨大潜力。据相关数据…

存储管理(一)

目录 一、存储管理的功能 1.地址映射&#xff08;地址重定位&#xff09; 2.主存分配和回收 3.存储保护 4.主存扩充&#xff08;虚拟存储&#xff09; 二、程序的装入与链接 程序的装入&#xff1a; 程序的链接 三、连续分配方式 单一连续分配 固定分区分配 动态分…

SpringBoot学习笔记3.27

目录 实战篇第二课 1.注册参数的校验&#xff1a; 学习过程中遇到的问题&#xff1a; 1.什么是正则表达式 2.怎么自定义异常&#xff1f; 1. 创建全局异常处理类 2. 定义响应对象 3. 使用 ExceptionHandler 4. 设置响应状态码 5. 返回统一响应 6. 测试全局异常处理 …

基于springboot+vue的游戏账号交易系统的设计与实现

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

小测验——合并多个网格文件调用相机参数进行适配

文章目录 一、前言1.1 对于rule1.2 对于ask、agent、edit1.3 对于没有notepad二、代码展示一、前言 1.1 对于rule 对于.cursorrules里面的文件内容,就是从提示词、项目简介、技术架构、目录结构、代码规范这几方面进行介绍 1.2 对于ask、agent、edit 切换模式在聊天框下方…

敏捷测试(Agile Testing)

敏捷测试&#xff08;Agile Testing&#xff09; 敏捷测试是在敏捷开发&#xff08;Agile Development&#xff09;环境下进行的软件测试方法&#xff0c;强调快速反馈、持续测试、团队协作&#xff0c;以确保软件质量贯穿整个开发周期。与传统瀑布模型不同&#xff0c;敏捷测…

FreeRTOS内核实现与应用学习之6——多优先级

在FreeRTOS中&#xff0c;数字优先级越小&#xff0c;逻辑优先级也越小&#xff1b;在任务创建时&#xff0c;会根据任务的优先级将任务插入就绪列表不同的位置。 相同优先级的任务插入就绪列表中的同一条链表中。 要想任务支持优先级&#xff0c;即只要实现在任务切换&#xf…

【C++篇】C++入门基础(二)

&#x1f4ac; 欢迎讨论&#xff1a;在阅读过程中有任何疑问&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;如果你觉得这篇文章对你有帮助&#xff0c;记得点赞、收藏&#xff0c;并分享给更多对C感兴趣的…

Mysql架构之日志讲解:redo log,undo log,bin log 日志

一、buffer pool缓冲区 讲日志之前&#xff0c;我们要先认识一下buffer pool缓冲区。 mysql想完成数据的修改&#xff0c;会先从存储引擎层读取数据&#xff0c;把数据读取到服务层进行数据的修改&#xff0c;再通过存储引擎层把数据更新到数据库中。 mysql每次读取数据都会…

容器主机CPU使用率突增问题一则

关键词 LINUX、文件系统crontab 、mlocate根目录使用率 There are many things that can not be broken&#xff01; 如果觉得本文对你有帮助&#xff0c;欢迎点赞、收藏、评论&#xff01; 一、问题现象 业务一台容器服务器&#xff0c;近期经常收到cpu不定期抖动告警&#x…

simpleITK - Setup - matplotlib‘s imshow

使用 matplotlib 显示内联图像 在此笔记本中&#xff0c;我们将探索使用 matplotlib 显示笔记本中的图像&#xff0c;并致力于开发可重复使用的函数来显示 SimpleITK 图像的 2D、3D、颜色和标签叠加层。 我们还将研究使用需要输入图像重叠的图像过滤器的微妙之处。 %matplot…

Github 热点项目 awesome-mcp-servers MCP 服务器合集,3分钟实现AI模型自由操控万物!

【今日推荐】超强AI工具库"awesome-mcp-servers"星数破万&#xff01; ① 百宝箱式服务模块&#xff1a;AI能直接操作浏览器、读文件、连数据库&#xff0c;比如让AI助手自动整理Excel表格&#xff0c;三分钟搞定全天报表&#xff1b; ② 跨领域实战利器&#xff1a;…

硬件老化测试方案的设计误区

硬件老化测试方案设计中的常见误区主要包括测试周期不足、测试条件过于单一、样品选择不当等方面。其中&#xff0c;测试周期不足尤为突出&#xff0c;容易导致潜在缺陷未被完全暴露。老化测试本质上是通过加速产品老化来模拟长期使用状况&#xff0c;因此测试周期不足会严重削…