本系列围绕Web前端安全对抗展开,上一篇介绍了传统Web反调试的各类短板以及整套协同防护体系的整体架构。本篇为系列第二篇,聚焦前端侧第一道防护:核心业务代码的模块化拆分与按需分发机制,讲解模块依赖DAG图谱的设计思路、时间窗口约束以及开发与运行阶段的整体流程。后续文章将继续介绍混淆加密、WASM隔离执行相关内容。
1. 前言
传统SPA单页应用在页面初始化阶段,会将全部业务JS代码一次性加载到浏览器环境中。
所有核心业务逻辑完整暴露在浏览器,攻击者只需要打开开发者工具,就可以拿到全部源码,进行阅读、断点调试、逆向分析。即便做了普通代码混淆,完整的代码集合仍然全部存在于前端环境,给逆向分析提供了充足素材。
如果我们不把全部业务逻辑一次性下发,而是将核心业务拆分为多个独立模块,存放在服务端,浏览器运行时根据业务流程按需请求对应模块,就可以从源头上减少前端暴露的代码总量。
同时通过定义模块之间的依赖调用关系,还可以在运行时校验代码执行顺序,识别调试中断、恶意篡改执行流程等攻击行为。
2. 什么是业务模块的模块化拆分
模块化拆分的核心原则是功能内聚、低耦合。
把前端的核心业务逻辑拆解成一个个原子化独立模块,每个模块只负责一块明确的业务能力,拥有清晰的输入输出,模块之间通过预先定义好的依赖关系协同工作。
举一个业务场景例子:
一个简单的支付流程,可以拆分为身份校验模块、订单生成模块、支付确认模块。
正常业务流程必须按顺序执行:身份校验 → 订单生成 → 支付确认。
不允许跳过前面的环节直接调用支付确认模块。
拆分不是简单的代码文件物理拆分,关键在于建立模块依赖图谱(DAG有向无环图),记录各个模块之间的调用先后约束。
3. 模块依赖DAG图谱设计
模块依赖图谱使用有向无环图来描述模块之间的依赖与调用顺序。
箭头代表执行依赖关系:箭头指向的模块,必须等待上游模块执行完成之后,才允许被调用。
开发阶段如何构建图谱
- 开展业务功能分析,梳理每一块业务的输入输出、前置依赖;
- 划分原子业务模块,明确模块边界,避免模块职责交叉;
- 定义模块之间的调用关系,生成 DAG 依赖图谱;
- 将拆分后的各个独立模块分别做混淆加密,存储至服务端。
图谱的价值不只是用于开发阶段的代码组织,更重要的是在浏览器运行时做执行流程校验。一旦出现违背图谱规则的调用行为,可以判定当前环境存在调试或者篡改风险。
4. 运行时时间窗口约束机制
仅仅约束模块调用顺序还不够。攻击者在调试的时候,会在两个模块执行中间打下断点,长时间暂停程序执行,分析中间变量与业务逻辑。
为此引入时间窗口约束:设定相邻两个模块执行的时间阈值。
当上游模块执行完毕之后,如果超过预设时间阈值,下游模块仍然没有被触发调用,则判定很可能存在人为调试中断行为,可以触发异常告警甚至熔断逻辑。
- 阈值可以根据业务场景灵活配置,不需要写死固定数值;
- 该机制用于识别人为断点暂停调试行为,不是用于普通业务正常执行耗时判断;
- 业务上存在用户手动交互等待的场景时,需要做特殊过滤,避免产生误判。
注意:时间窗口约束属于风险辅助判断条件,不单独作为拦截依据,需要和其他校验条件结合使用,降低误判概率。
5. 开发阶段与运行阶段完整流程
开发阶段
- 业务需求分析,梳理各个业务功能的职责边界;
- 完成模块划分,定义每个模块的入参、出参、对外接口;
- 梳理模块依赖关系,构建 DAG 模块依赖图谱;
- 模块编码,单元测试;
- 对每个独立模块做混淆加密,全部存放到服务端,浏览器初始加载不会拉取这些核心业务模块。
运行阶段
- 浏览器初始化,仅加载基础框架代码,不加载加密业务模块;
- 当业务流程需要执行某一个模块时,浏览器向服务端发起模块请求;
- 服务端完成合法性校验之后,返回加密后的模块数据;
- 前端解密模块并执行,同时记录模块执行完成状态;
- 根据 DAG 图谱校验下一个模块的调用是否符合依赖规则,同时监测模块之间执行的时间间隔;
- 一旦检测到非法调用或者超时异常,进入异常处理逻辑。
6. 该方案的收益与现实局限
收益
- 浏览器初始化不会加载全部核心业务代码,减少静态逆向可获取的源码;
- 通过 DAG 图谱约束模块调用顺序,识别被篡改的执行流程;
- 时间窗口约束可以辅助识别断点调试暂停行为;
- 模块按需加载,模块粒度可控,便于后续加密、隔离执行能力扩展。
局限
- 需要在前期投入成本做业务模块拆分,对项目前期架构设计有一定要求;
- 用户操作交互等待场景,如果阈值设置不合理会带来误判,参数需要结合业务调优;
- 本机制属于防护体系其中一环,不能单独完成完整反对抗防护,需要和加密、WASM 隔离、后端校验配合使用。
7. 系列后续内容预告
- 第三篇:解析多层混淆加密、WASM 动态加载执行,以及内存隔离、本地异常熔断的实现思路;
- 第四篇:聊聊设备环境特征采集,如何将设备特征和动态凭证结合,抵御重放攻击;
- 第五篇:服务端接口调用约束,如何校验接口的调用顺序,拦截非法请求链路;
- 第六篇:长连接协同、分布式熔断机制,完整梳理整套体系的落地权衡与方案总结。
本文为系列第二篇,主要讲解前端代码模块化拆分与模块依赖图谱相关设计,下一篇我们介绍模块的加密处理以及 WASM 隔离执行相关内容。