从__NEXT_DATA__到ServerActions:Next.js攻击面研究笔记

admin 2026-03-26 13:24:55 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文系统研究Next.js攻击面,指出框架收敛多能力导致边界变薄。关键发现包括__NEXT_DATA__数据泄露、资源代理SSRF风险、ServerActions权限缺陷、缓存边界错误及SourceMap暴露敏感信息。文章提出优先检查数据传递、资源代理和缓存行为的测试路径,强调先看清行为再测试的原则,为安全研究者提供了系统化的Next.js安全审计方法论。 综合评分: 87 文章分类: 渗透测试,WEB安全,红队,安全建设,实战经验


真实项目里为什么容易埋坑

开发团队往往为了方便,会希望:

  • 支持更多图片来源
  • 支持第三方 CDN
  • 支持更多资源站点
  • 支持自动重定向和兼容

一旦这些能力越开越宽,边界就容易松。所以你在测 Next.js 时,只要看到框架在“替用户取资源”,脑子里就要亮灯。不是说一定有问题,而是这种设计天然更值得安全研究员多看两眼。

你重点看什么

  • 来源限制是不是过宽
  • 是否允许跨域资源来源太多
  • 是否存在可控跳转链
  • 是否存在可被服务端拉取的远程地址
  • 是否还有文件类型、SVG、内容处理等附加风险

这类点一旦出问题,通常不只是“拿一张图片”这么简单,它往往会往更高价值的方向扩展。


七、不要把 Server Actions 只当成新语法

很多人第一次看到 Server Actions,会把它当成一个开发体验优化。其实从安全视角看,它更像是:**把一部分原来需要接口承载的服务端操作,换了一种形式暴露出来。**这就意味着一个关键点:原来接口该有的安全问题,它大概率也还是会有,只是表现形式不一样。

为什么它值得重点研究

因为它让“前端触发服务端动作”这件事变得更自然了。自然的另一面,就是开发者更容易忽略边界,比如:

  • 这个动作到底该谁触发
  • 来源校验做没做
  • 权限校验是不是写在服务端真正入口上
  • 某些情况下会不会被错误转发或错误重定向

一个简单例子

开发者原本可能会写一个 /api/update-profile 接口。后来换成 Server Actions 之后,前端看起来只是“点一下按钮”,后面却还是发生了真实的服务端状态变更。这时候研究员该问的不是“这语法新不新”,而是:

  • 谁能触发它
  • 触发条件是什么
  • 服务端有没有独立做权限判断
  • 请求来源和宿主信息有没有被错误信任

如果再说得更短一点,Server Actions 值得看的原因,往往不是因为它“新”,而是因为它让很多原本看起来像接口的事情,不再以传统接口的样子出现了。入口样子变了,边界问题通常并不会一起消失。

实战里为什么要盯紧它

因为这种新能力经常会出现两个问题:

  1. 开发者习惯还没完全跟上
  2. 生态周边的最佳实践还没完全沉淀

所以你会看到一些项目里,用法是新的,边界却还是旧的,结果就会出事。如果目标是较老版本、或者工程质量一般的项目,Server Actions 往往值得认真翻。


八、缓存问题经常比表面上更有研究价值

很多人一提缓存,第一反应是性能,不是漏洞。但在现代 Web 里,**缓存配错了,经常能直接变成安全问题。**而 Next.js 又很依赖缓存思路,所以这一块尤其不能放过。

为什么缓存会出问题

因为缓存机制本质上做的是一件事:

这次请求的结果,下次能不能直接拿来复用。

问题就出在“复用边界”上。如果系统没分清:

  • 哪些内容是公共的
  • 哪些内容是用户私有的
  • 哪些 header 会影响结果
  • 哪些页面不该被共享

那就有可能出现:

  • 本该只给一个用户的内容,被缓存给别人
  • 本该受上下文影响的页面,被按公共资源缓存
  • 某些可控输入进入缓存结果,影响后续访问者

一个最容易理解的例子

假设 /dashboard 页面本来应该是登录后用户自己的页面。但如果缓存层把它当成公共页面处理了,那么理论上就可能出现:

  • 用户 A 访问后生成了一份缓存
  • 用户 B 再访问时拿到的是这份缓存结果

你真正要测试的,不是“缓存有没有存在”,而是:**缓存有没有把不该共享的东西共享出去。**同样地,如果一个站点的订单页、个人中心页、后台概览页在响应头上都表现得像公共资源,那你就不该再把它只当成性能问题,而应该开始怀疑:这里是不是把用户态页面缓存成了可复用页面。

为什么 Next.js 更值得看缓存

因为它本身就鼓励很多性能优化思路:

  • 静态生成
  • 增量更新
  • 边缘缓存
  • 页面复用
  • 数据缓存

这些本身都没错,但只要“个性化内容”和“公共缓存”边界没划清,问题就会开始冒出来。

你重点看什么

  • 个性化页面是否出现公共缓存特征
  • 登录态内容是否被错误复用
  • 某些 header 是否能影响缓存内容
  • 页面是否存在不该共享的用户数据

缓存问题的魅力在于:**它经常不是“一个点打穿”,而是“一个配置理解错了,整个行为都偏了”。**这种问题在赏金里很讨喜,因为如果你能证明影响范围,价值通常不低。


九、Source Map 依然是一个很好用的观察窗口

很多研究员会下意识觉得 Source Map 是“老问题”,好像不够高级。但我一直觉得,这类问题的价值不在于它是不是新,而在于:它能不能把原本看不清的前端逻辑,重新摊开给你看。

它的意义是什么

前端打包之后,代码经常已经压缩、混淆、拆块了。你直接读那些产物,很费劲,也很容易漏东西。一旦 Source Map 泄露,你看到的就不再是一团打包产物,而更接近开发者原本写出来的结构。这意味着什么?

  • 更容易看清真实路由和调用关系
  • 更容易发现隐藏接口
  • 更容易发现调试逻辑
  • 更容易看到命名语义
  • 更容易顺着代码看权限和功能边界

一个很现实的价值

在没有 Source Map 的情况下,你可能只能看见一坨压缩后的变量名。有了 Source Map 之后,你更容易直接看到类似这样的语义:

  • adminApi
  • debugMode
  • internalBaseUrl
  • useServerAction

这会极大缩短你理解业务结构的时间。

为什么它在 Next.js 里有价值

因为 Next.js 项目通常前端逻辑不少,打包以后可读性下降很明显。一旦恢复结构,很多本来“只能猜”的东西,会直接变成“肉眼可读”。

一个很常见的变化是:原本你只能模糊地猜测“这里可能有个内部接口”,有了 Source Map 之后,这种猜测会迅速变成更具体的观察——接口名是什么、调用发生在哪里、它和哪个页面状态绑定在一起。对研究员来说,这种差别往往就已经足够大了。

你该怎么用这个线索

不要把它只当成“信息泄露”本身。更好的思路是:**把它当成后续所有测试的放大镜。**它不是终点,而是让你后面更快找到高价值点的工具。

十、内容渲染链经常决定问题会不会浮出来

如果一个 Next.js 项目里存在这些功能:

  • 博客发布
  • 评论系统
  • 富文本编辑
  • Markdown 渲染
  • 可视化内容编辑
  • CMS 内容同步

那你几乎就应该立刻想到一件事:内容是怎么进 DOM 的。

为什么这里容易出问题

因为 React 默认是会帮你做一层转义的,这本来是好事。但很多业务为了显示格式化内容,会主动绕开这层保护,比如:

  • 把 Markdown 转成 HTML 再渲染
  • 允许后台内容带样式或标签
  • 做富文本预览
  • 引入第三方内容编辑器

一旦这条链里有一环做得不稳,XSS 风险就会出现。

一个简单例子

假设开发者把用户输入的 Markdown 转成 HTML 后,直接塞进页面。从功能角度看,这是“让内容显示得更漂亮”。从安全角度看,这就是在问:

  • HTML 有没有被净化
  • 哪些标签和属性被保留了
  • 最终是以什么方式进入 DOM 的

这类问题不一定靠爆 payload 才能发现,很多时候看清渲染链本身,就已经很接近答案了。

你不要只盯着“输入框”

这类问题不一定只出在用户手填内容上,也可能出在:

  • 后台导入的数据
  • 第三方 CMS 同步内容
  • 营销活动模板
  • 帮助中心或公告系统

也就是说,越是“看起来像内容系统”的页面,越值得多看渲染链。


十一、工程侧线索有时比页面本身更诚实

Next.js 项目往往和 Node.js 生态深度绑定,所以它不仅有运行时攻击面,也会有很强的工程侧线索。比如:

  • 包管理文件
  • 配置文件
  • 环境变量痕迹
  • 私有包命名
  • 构建与部署信息

为什么这部分重要

因为很多时候,你不是直接从“漏洞利用”里拿结果,而是从“工程侧泄露”里拿线索。这些线索可能不会立刻变成一个洞,但它们经常能告诉你:

  • 项目依赖了什么
  • 开发团队怎么组织工程
  • 有没有私有包和内部体系
  • 有没有暴露出进一步分析的入口

一个常见思路

如果你拿到了依赖、配置、构建痕迹,这些信息本身可能不算最终结果。但它们会帮你更快判断:

  • 哪些组件值得深看
  • 有没有版本相关的历史问题
  • 有没有内部包、内部路径、内部命名体系

也就是说,它们不一定是漏洞本身,但常常是高价值漏洞的路标。

这类点的价值在哪

在高质量目标里,工程信息往往比表面页面更诚实。页面会伪装,构建产物和配置痕迹通常不会。所以你在看 Next.js 项目时,不要只盯着页面和接口,也要保留一个工程视角:这套东西是怎么被构建、被组织、被部署出来的。

再举一个很短的例子:假设你没有直接找到洞,但你从构建痕迹里看到了 internal-admin-sdkstaffOnlyApidebugToolbar 这类命名。它们本身可能还不构成结果,但对研究员来说,这已经足够说明两件事:

  • 这个项目大概率有内部能力和外部能力的分层
  • 这些分层未必在每个入口都做对了隔离

很多时候,真正有价值的发现,不是从首页一路打进去,而是先从这些工程侧线索里闻到“哪里可能有内部边界”。


十二、如果要实战起手,可以按这个顺序看

如果你已经确认目标是 Next.js,但还不想一上来就把时间花在很散的枚举和试探上,一个更稳的起手方式通常是:先确认框架痕迹,再看页面怎么拿数据,再看那些最容易暴露边界问题的位置。

第一步:先确认它是不是 Next.js

很多时候这个并不难。

你可以从下面这些痕迹判断:

  • 页面源码里有没有 __NEXT_DATA__
  • 静态资源路径里有没有 _next/static
  • 页面和资源结构是否符合 Next.js 常见特征

先确认技术栈,后面很多动作才有针对性。

第二步:先看源码,不要急着打

重点看:

  • __NEXT_DATA__
  • 页面里是否带了过多数据
  • 是否能看出服务端渲染痕迹
  • 是否能看出运行时配置

第三步:看 JS 和前端调用关系

重点不是“把 JS 全下载一遍就结束”,而是弄清楚:

  • 页面会调哪些接口
  • 哪些接口像内部管理接口
  • 哪些功能只在前端做了限制
  • 哪些内容渲染链看起来不太稳

第四步:看特殊特性

也就是 Next.js 特别值得看的那些东西:

  • 图片优化
  • Server Actions
  • 中间件
  • 缓存行为

第五步:最后再做更细的深挖

比如:

  • 缓存问题验证
  • 权限与身份边界验证
  • 多角色、多账号对照测试
  • 老版本特性的兼容问题

这个顺序的核心其实很简单:

先看清行为,再决定怎么测。

这样做不一定最炫,但在真实目标里通常更省时间。

十三、如果刚开始研究,可以先把这三个点练熟

如果你刚开始研究 Next.js,我建议你先别想一步到位全掌握。先把下面三个点练熟,性价比最高。

1. __NEXT_DATA__ 数据审计

因为这是最容易上手,也最能帮你建立 Next.js 安全感觉的点。你只要开始认真看这类数据结构,很快就会对“哪些东西本来不该被前端看到”形成直觉。

2. 内容渲染链

因为这个最容易帮助你把 React、前端渲染和 XSS 风险串起来。你会慢慢明白:不是 React 天生安全,而是 React 默认帮你挡了一层;一旦业务主动绕开,问题就回来了。

3. 缓存和页面复用逻辑

因为这个最能拉开你和普通测试者的差距。很多人只会盯着输入输出,而不会看缓存边界。但真正高价值的问题,往往就藏在“这个页面为什么会被复用给另一个人”这种地方。

十四、一个常见误区:不要把 Next.js 只当成“换皮 React”

这是一个很常见的误区。如果你只是把 Next.js 当成 React 的套壳,那你会天然忽略掉很多服务器侧和框架层问题。更准确的理解应该是:**Next.js 是一个把前端体验、服务端能力、缓存机制和工程能力揉到一起的框架。**这意味着你测它的时候,也要用一个更立体的脑子:

  • 既看前端
  • 也看后端
  • 既看页面
  • 也看框架行为
  • 既看接口
  • 也看缓存与渲染路径

一旦你这么看,很多原来你以为“只是个前端项目”的目标,会突然变得很有意思。


十五、最后总结:真正值得研究的,通常不是功能本身,而是边界

如果只用一句话概括 Next.js 的安全研究重点,我更倾向于这样说:

不要急着把它拆成一串漏洞名词,先去看边界是怎么被处理的。

这个框架里反复出现问题的地方,往往都和边界有关:

  • 服务端和前端的边界
  • 公共数据和私有数据的边界
  • 本地资源和远程资源的边界
  • 用户请求和服务端代请求的边界
  • 动态页面和缓存页面的边界

当这些边界被处理得足够清晰时,很多问题不会出现;但当这些边界被藏进抽象层、默认配置或者“图方便”的工程写法里时,问题就会开始以一种不太显眼的方式浮出来。

这也是为什么 Next.js 值得研究。

它并不是一个“天然更危险”的框架。更准确地说,它是一个很容易把复杂能力收敛到一起的框架,而只要能力收敛得足够多,研究员就有必要重新检查:哪些事情被简化了,哪些边界也在这个过程中一起被简化了。

所以如果你后面还会继续看 Next.js,一个很有用的习惯通常不是先问“今天我要找什么漏洞”,而是先问:

这里原本应该清晰分开的东西,现在是不是被框架替我揉到一起了?

很多真正有研究价值的发现,往往就是从这个问题开始的。

如果这篇文章能帮你建立起这个观察角度,那它的目的就已经达到了。

附:一个更适合实战的 Next.js 快速检查清单

基础识别

  • 这个目标是不是 Next.js
  • 页面里有没有 __NEXT_DATA__
  • 静态资源里有没有 _next/static
  • 是否能看出 SSR、静态生成或其他渲染痕迹

数据暴露

  • 页面源码里有没有多余数据
  • 用户对象有没有带过多字段
  • 有没有内部地址、调试字段、配置项
  • 有没有明显不该暴露给前端的运行信息

前端与渲染链

  • 富文本/Markdown 是怎么渲染的
  • 有没有主动绕开默认转义
  • 有没有内容直接进 DOM 的链路
  • 有没有高风险编辑器或模板场景

服务端代请求能力

  • 框架是否替用户拉远程资源
  • 图片、文件、远程内容处理边界是否过宽
  • 是否存在值得深挖的来源校验问题

新特性与权限边界

  • 是否使用 Server Actions
  • 状态变更动作的边界是否明确
  • 是否只做了前端限制,没有做服务端兜底

缓存行为

  • 个性化页面是否存在公共缓存痕迹
  • 缓存键是否合理
  • 是否存在页面复用给错误用户的可能
  • 是否有可控输入影响缓存结果

工程侧线索

  • 是否有 Source Map 暴露
  • 是否能看出依赖和构建结构
  • 是否存在配置痕迹、包管理线索、环境信息线索

参考方向: Next.js 官方文档、真实项目源码、框架版本更新日志、公开安全研究文章、缓存与渲染相关案例分析。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:Zacarx随笔 Zacarx Zacarx《从 NEXT_DATA 到 Server Actions:Next.js 攻击面研究笔记》

评论:0   参与:  0