文章总结: 本文系统梳理了Vue、React、Angular、Node.js、Express、TypeScript、Next.js等主流前端框架的安全审计要点,核心结论是前端控制不可信,真正漏洞均在API接口。通过React+Node.js未授权删除、前端金额校验绕过、Angular双向绑定提权等典型漏洞案例,强调后端必须独立鉴权与参数校验,前端仅用于枚举接口与辅助定位攻击入口,实际审计应抓包直调API。 综合评分: 78 文章分类: 代码审计,WEB安全,安全建设,实战经验,应用安全
代码审计之前端框架篇
原创
uuwan uuwan
SecurityBug
2026年2月8日 10:01 陕西
▲ 点击上方SecurityBug蓝字关注和✩星标,以防失联~
**未经同意禁止转载,代码片段建议电脑端阅读~
请点击文末 #代码审计 标签或公众号消息菜单查看合集,如果对您有帮助还请点赞、在看、评论、转发、打赏哦,您的互动就是我更新最大的动力!
目录如下:
框架介绍
1
#
Vue/Vue.js
一句话:
Vue 是 前端写网页界面的工具,负责“页面怎么长、点了按钮发生什么”
Vue.js 是用 JavaScript 写的一个前端框架,Vue.js 是一堆别人写好的 JavaScript 代码,帮你更方便地写网页交互
写的是浏览器里跑的代码不直接接数据库不直接做权限判断(大多数时候)
👉 对代码审计来说:Vue 本身不是重点攻击面
**2
#
Node.js/Node**
一句话:
Node.js 是 用 JavaScript 写后端服务 的运行环境。
可以写接口可以操作文件可以连数据库可以写 CLI / 后台服务
👉 对代码审计来说:
-
Node.js 是实打实的攻击面(而且坑很多)
-
这是 前端代码 还是 后端代码
-
鉴权是不是写在中间件里
-
这个接口是不是 Node 写的,有没有:
-
app.use()
-
中间件顺序
-
req.body / req.query
3**
#
Express****
本质:Node.js 上的一个“框架”,帮你更容易写后端接口
Node.js 是砖和水泥Express 是你盖楼用的模板/管道/工具
审计角度:Express 里的路由 /api/…、中间件顺序,决定接口安全
4
#
*React*
React 是一个开源的 JavaScript 库,用于构建用户界面(UI),尤其擅长创建交互式、组件化的 Web 应用程序。
React 是一个“用来写网页界面”的工具库
👉 负责:页面长什么样、点了按钮发生什么👉 不负责:鉴权、安全、数据库、权限校验
不用 React 的网页是怎样的?
- HTML 写死页面
- JS 操作 DOM
- 页面一复杂就一团乱
React 的核心思想
- 数据变了
- 页面自动跟着变
React 就是帮你管理:
- 页面状态(state)
- 页面更新
- 组件之间的数据传递
React 在项目里一般长这样:
你看到这些关键词,就知道是 React:jsx / tsxuseStateuseEffectpropscomponent
</head><body> <!-- 渲染目标 --> <div id="root"></div>
<!-- React 代码 --> <script type="text/babel"> // 一个简单的 React 组件 function Welcome(props) { return <h1>Hello, {props.name}!</h1>; } // 使用组件 const element = <Welcome name="Alice" />; // 渲染到页面 ReactDOM.render(element, document.getElementById('root')); </script></body></html>
结果:Hello, Alice!
示例一:最经典的 React + Node.js 后端未授权漏洞
🧩 场景
这是一个 后台系统:
- 管理员:可以删用户
- 普通用户:不可以
一、前端(React)代码在干嘛?
{ user.role === 'admin' && ( <button onClick={() => deleteUser(id)}>删除</button>)}
//只有当你是管理员,页面上才会显示“删除”按钮user.role === 'admin' //当前登录的这个人,是不是管理员?&& //“如果前面是真的,才继续往下做”<button>删除</button> //页面上显示一个 “删除”按钮onClick={() => deleteUser(id)}//当你点这个按钮时:调用一个函数,去请求后端,告诉后端:“我要删 id 这个用户”
二、后端代码在干嘛?(漏洞就在这里)
原代码(Node.js 后端)
app.post('/api/user/delete', (req, res) => { deleteUserById(req.body.id); res.send('ok');});
app.post('/api/user/delete', ...) //后端提供了一个接口:“谁访问 /api/user/delete,我就执行下面的代码”(req, res) => {...} //req:用户发来的请求(参数、身份)res:我要回给用户的结果req.body.id //从用户发来的请求里,取一个参数:要删除的用户 iddeleteUserById(req.body.id); //直接删除这个用户res.send('ok'); // 告诉调用者:“删完了,成功”
三、漏洞为什么成立?(关键逻辑)
开发者以为:“普通用户看不到删除按钮,所以删不了人”
实际上:
- 前端按钮 ≠ 安全
- 后端接口谁都能调
四、攻击者是怎么绕过 React 的?
攻击者 根本不看页面
直接对后端发请求: 后端一看:有请求、有 id、直接删。
未授权删除成功。
POST /api/user/deleteContent-Type: application/json{ "id": 1}
示例二:前端校验金额,后端信任 → 逻辑漏洞
一、前端(React)代码
function onSubmit() { if (amount > 10000) { alert('不能超过 1 万'); return; } submit({ amount });}
//前端的“安全措施” 限制用户只能填 ≤10000if (amount > 10000) //如果金额 大于 10000alert('不能超过 1 万'); //弹窗提示用户:“不允许”return; //停止提交,不发请求, 立刻结束 onSubmit() 这个函数submit({amount}); //把金额发给后端
二、后端代码(问题来了)=
amount = request.json['amount']process_payment(amount)
request.json['amount'] // 从用户请求里直接拿金额process_payment(amount) // 按这个金额去处理支付 没再检查一次金额范围
三、攻击者怎么绕?
攻击者不走前端页面,直接发请求:后端照单全收,金额被任意篡改
{ "amount": 99999999}
### 示例三:前端传 “我是不是管理员”,后端直接信(超高危)
一、前端
api.updateUser({ id: 123, role: 'admin'});
前端告诉后端:“我要把这个用户123设成 admin”
二、后端(致命)
const role = req.body.role;user.role = role; // 直接改数据库里的角色save(user);
攻击者请求 直接提权成功
{ "id": 123, "role": "admin"}
前端:只能“提示”和“展示”
后端:必须“判断”和“兜底”
你以后只要看到这种组合,就要警觉
| | | | | — | — | — | | 前端行为 | 后端行为 | 结果 | | 判断角色 | 后端不判断 | 未授权 | | 校验参数 | 后端不校验 | 逻辑漏洞 | | 隐藏按钮 | 接口可直调 | 越权 |
5
#
*TypeScript*
先说 JavaScript 的一个老毛病,JavaScript 本身是:
不检查类型,变量想变啥就变啥写起来快,出 bug 也快
比如(纯 JS):
let user = getUser();user.isAdmin(); // 实际 user 可能是 null,运行时直接炸
TypeScript 做了什么?TypeScript 在 JS 上面加了一层:
- 类型
- 编译期检查
- 更严格的约束
type User = { isAdmin: () => boolean};let user: User | null = getUser();user.isAdmin(); // ❌ 编译阶段就报错
let user: User | null = getUser();user 这个变量,有两种可能:它是一个 User 对象它是 null(没有用户)人话:“getUser() 可能返回一个用户对象,也可能什么都没有(null)”
user.isAdmin(); // ❌ 报错TypeScript 报错原因:你不能直接对一个可能为 null 的变量调用函数假设 user = null如果执行 user.isAdmin() → JS 会崩掉报 Cannot read property 'isAdmin' of nullTypeScript 就在编译阶段说:“嘿,你写的这个代码可能会炸!别傻呼呼地运行!”
还没跑起来,问题就被揪出来了
只要是:中大型 Web 项目、To B 系统、维护周期 > 1 年👉 90%+ 都在用 TypeScript
6
#
*Next.js(React + Node.js)*
- 它让你用 React 写前端页面
- 同时可以在 Node.js 上写后端接口
- 简单理解:前端 + 后端 = 一体化框架
Next.js 本质上就是 React + Node.js,所以漏洞类型和你之前学的 React + Node.js 漏洞一模一样:
🔹 前端部分
-
所有 React 的问题依然存在:
-
按钮隐藏 ≠ 权限控制
-
前端校验 ≠ 后端校验
-
Vue / React / Next.js 的模板逻辑只影响展示
🔹 后端 API
- Next.js 内置的 /pages/api/* 本质是 Node.js 函数:
export default function handler(req, res) { const user = getUser(req.body.id); res.status(200).json(user);}
req:表示 HTTP 请求对象, 包含请求的所有信息(如请求体、查询参数、请求头等)。res:表示 HTTP 响应对象,用于设置返回的内容和状态码。
req.body.id 表示请求体中的 id 字段,通常是用户的唯一标识。getUser(req.body.id) 通过提供的 id 来获取该用户的数据。res.status(200) 设置响应的状态码为 200,表示请求成功。.json(user) 将 user 对象转换成 JSON 格式,并返回给客户端。
如果没有鉴权 / 参数校验 → 未授权、越权、逻辑漏洞,攻击者绕过前端,直接访问 /api/… 就能触发漏洞
7
#
*Angular*
Angular = 一整套前端框架,类似 Vue.js / React,但更“全能”,官方自带很多功能。
Angular 的漏洞,99%不是 Angular 框架本身的问题,而是「前端当安全、后端没锁门」的问题
### 示例一:前端 *ngIf 做权限判断(经典未授权)
场景代码(Angular 前端)
<button *ngIf="user.isAdmin" (click)="deleteUser(1001)"> 删除用户</button>
*ngIf="user.isAdmin":👉 只有管理员才显示这个按钮deleteUser(1001):👉 点按钮就删除 id=1001 的用户开发者以为:“普通用户看不到按钮 = 不能删人”但实际上:Angular 只是控制“显示不显示”,接口仍然存在
后端接口(Node / Java / whatever)
POST /api/deleteUser{ "id": 1001 }
如果后端没校验当前用户是不是管理员:deleteUser(req.body.id); // 直接删
攻击者直接调用该接口: 删除成功 未授权漏洞POST /api/deleteUser{ "id": 1001 }
### 示例二:双向绑定导致越权(参数可控)
Angular 前端代码
<input [(ngModel)]="user.role"><button (click)="save()">保存</button>save() { this.http.post('/api/updateUser', this.user);}
[(ngModel)]="user.role" 输入框里的值 直接写进 user.role点击保存 → 整个 user 对象发给后端
攻击者怎么做?
正常用户页面里可能是:{ "id": 1001, "role": "user"}
攻击者用抓包工具改成:{ "id": 1001, "role": "admin"}
updateUser(req.body); // 后端如果这样写等于直接信任前端普通用户 → 管理员 垂直越权
Angular 双向绑定 ≠ 安全后端必须重算权限,不能信前端字段
### 示例三:路由守卫当权限(假的安全)
Angular 路由守卫
canActivate(): boolean { return this.authService.isLogin();}
canActivate()函数名,Angular 规定的名字意思是:“我能不能激活(进入)这个页面?”: boolean 表示这个函数 只会返回 true 或 falsetrue = 允许进入页面 false = 不允许进入页面
return this.authService.isLogin();拆开来看:authService一个“认证服务”,专门用来判断:用户有没有登录isLogin()返回:true:已登录 false:没登录
这段代码的意思是:在路由激活之前,判断 authService 服务的 isLogin() 方法返回值来决定是否允许用户进入该路由。如果用户已经登录,允许访问;如果没有登录,则不允许访问。这个能防攻击吗?
不能。因为这个判断 :
只发生在浏览器里攻击者根本不需要进页面他可以直接访问后端接口
前端(Angular) 你没登录,页面不给你看
攻击者 GET /api/admin/users
后端如果没校验:getAllUsers(); // 直接返回攻击成功 未授权漏洞
审计重点
- 请求入口在哪里
- 鉴权 / 权限在哪里
- 参数是怎么绑定的
- 数据是怎么进数据库的
- 全局配置是否真的生效
- 真正要审的是:API 接口、请求发送逻辑、Token / Cookie 使用方式
实际工作中,几乎不会“审计前端框架代码”
抓包直接打接口,才是性价比最高的方式
前端代码基本都是:
压缩(minify)混淆(uglify / terser)打包成一坨 JS
看起来像这样:可读性极差,没审计价值
function(a,b){return a&&b?c(d(e)):f}
前端写得再严,攻击者也不会按前端来
前端限制参数、 前端隐藏按钮、前端拦跳转
抓包一改,全没用
真正的漏洞一定在API接口
1
#
*那前端用途在哪?*
用前端“枚举接口” ,找接口列表
右键 Network 面板搜索1. /api2. fetch / axios3. admin / manage4. login / auth5. confirm / submit6. id / userId7. debug / test
注意以下接口fetchXMLHttpRequestxhr/api/api//v1/v2/rest/rpc/service/services/backend/internaladminmanagemanagerrootsupersystemconfigsettingsettingsloginlogoutauthtokenjwtsessionrolepermissionprivilegeuseraccountprofilepaypaymentordertradetransferwithdrawrefundbalanceamountpriceiduiduserIdaccountIdorderIditemIdfileIdresourceuploaddownloadexportimportfilepathurlstatusstatestepconfirmsubmitapproverejectauditreviewprocessdebugtestdevmocktmptempdemoexample
推测参数结构,然后你去抓包、改包、重放
{ "userId": 1001, "role": "user", "amount": 9999}
判断业务逻辑,帮你定位攻击入口
1️⃣ 正常操作一次,抓全包
2️⃣ 看一次操作发了几个请求
3️⃣ 按顺序重放请求
4️⃣ 改参数 / 跳步骤
5️⃣ 看哪一步真的生效
2
#
*真实工作流*
不信前端 → 抓包 → 直接打接口
打开页面
↓
操作一遍正常流程
↓
抓所有 API
↓
脱离前端,直接请求
↓
未授权 / 越权 / 重放 / 改参数
因此前端框架只要“识别级”即可
看见 v-if / *ngIf / canActivate 脑子里自动翻译成:“前端限制,不可信”看见 ngModel / v-model “参数前端可控”看见 axios / fetch “接口在这”
### 最后宣传一下我的新书!目录如下! **
**
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:SecurityBug uuwan uuwan《代码审计之前端框架篇》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论