ThinkPHP8 + 原生 JS:前端主导的异步表单安全防护实践(防 CSRF / 篡改 / 重放)

ThinkPHP8 + 原生 JS:前端主导的异步表单安全防护实践(防 CSRF / 篡改 / 重放)
28.7的博客前端安全防护实践:防御未授权访问与数据篡改
这些是可以增加校验的额外方法,不使用不影响本节内容,仅作为暂时补充
中间件kong 以及konga安装部署方法
中间件认证的基础插件
加强密钥管理,避免敏感信息泄露
增强数据校验以及数据库存储数据的安全性
Gitea安装部署
Git 安全使用
JumpServer终端审计录像以及回访
Zabbix服务器监控
背景与目标
2025-10-14 12:05:16 星期二
本文基于ThinkPHP8,以及原始Javascript,在传统的表单验证中,或者是说在我以前的时候,使用简单的异步请求,导致前端发送的数据完整性处于未知状态,也就是说从前端离手,到后端接手这个过程中,
- 第一时间未知:当前端发送表单数据后,即使过了一个小时?两个小时?由于未作时间校验,我无法对此进行判断
- 数据完整性未知:当用户发送完表单数据,是否在中途被篡改,这也是未知的
- 重放行为:由于未做ssrf,从前端来看就容易被二次使用,所以这也是未知的
总结,我希望在这份笔记从前后端的交互中解决上述问题,重点在前端,为什么是前端,在整个信息系统与交互的友好性以及Js的灵活性上看,其承担的意义还是十分明显的
- 动态内容更新,减少冗余交互传统静态页面依赖 “请求 - 刷新” 模式(如早期 PHP、JSP 页面),用户每操作一次(如切换选项、提交表单)都需要重新加载整个页面,体验卡顿且效率低下。JavaScript 通过操作 DOM(文档对象模型),可以在不刷新页面的情况下直接修改局部内容(如动态加载列表、切换标签页、更新数据统计)。例如:电商平台的 “加入购物车” 按钮点击后,无需刷新页面即可更新购物车数量,大幅减少用户等待时间。
- 即时反馈,降低用户操作成本信息系统的交互效率很大程度上依赖 “操作 - 反馈” 的及时性。JavaScript 支持客户端实时验证(如表单输入校验),用户输入手机号、邮箱时可即时提示格式错误,无需等待服务器响应,减少无效提交;同时支持动态提示(如搜索框的联想建议、输入框的字数统计),引导用户更高效地完成操作。
- 异步通信(AJAX),优化数据交互模式借助 XMLHttpRequest 或 Fetch API,JavaScript 实现了客户端与服务器的异步数据交换:用户操作时,JS 可在后台悄悄发送 / 获取数据,不阻塞页面其他操作。例如:社交平台的 “下拉加载更多” 功能,用户滑动页面时,JS 异步请求新数据并渲染,既保持页面流畅,又实现数据增量更新,避免一次性加载大量数据导致的性能问题。
- 数据验证:JavaScript支持复杂的函数以及异步方法,通过这些方法我们可以完成复杂的混淆逻辑以及验证逻辑,同时减少Python 带来的自动化攻击,同时也实现数据校验,保证性能的同时大大提高破解复杂度以及安全性
1. JavaScript事件处理机制 2. Token注入策略以增强访问控制 3. 数据加密与完整性验证 4. 时效性验证
基础异步表单提交分析
初始代码实现
假设我们有一段数据交互逻辑,就将其当作统一认证的表单,这是一段经典的异步交互代码,收集表单数据,传递表单信息,在这个代码之中,我们存在上述的所有可能情况
1 | <form id="userForm" class="space-y-4"> |
1 | const form = document.getElementById('userForm'); |
由于问题存在后端,时效性未校验,未增加token口令以及明文信息的传递导致数据轻易被抓包,被重放被爆破修改
1 | public function login() |
安全风险识别
基础实现存在以下安全隐患:
- 中间人攻击:用户敏感数据明文传输
- 重放攻击:请求可被截获并重复使用
- 数据篡改:请求参数可被恶意修改
在下面的教程中,我们逐级拆解我们所做的事情,从一级到四级逐级完善。每一个章节都有较为完整的代码以及实现核心和防护效果
1. CSRF Token防护
做csrf 是为了避免重放攻击,每一次的http请求头仅允许第一次有效,减少黑客试错的机会,提高复杂度
后端实现:app\controller\Index控制器
1 |
|
前端集成:
1 | <form id="userForm" class="space-y-4"> |
js代码保持不变
1 | const form = document.getElementById('userForm'); |
2. 前端数据加密
Base64邮箱编码
- btoa方法
为了保证安全与体验的平衡,邮箱由于后面还需要进行多因素认证,所以需要可逆的,这里仅仅选中base64编码方式
表单与后端保持不变
1 | <script src="https://cdn.jsdelivr.net/npm/crypto-js@4.2.0/crypto-js.min.js"></script> |
1 | <script src="https://cdn.jsdelivr.net/npm/crypto-js@4.2.0/crypto-js.min.js"></script> |
防护三:hash256 数据校验,时效性验证,动态口令验证,数据格式验证
在这里,我设在前端设置两个方法
getHashSalt():从后端fetch 一段随机高强度的selt加盐(MD5的timestamp格式)calculateHash(text):text参数拼接编码后的邮箱密码以及用户名进行sha256的hash计算,保证数据完整性
在此,我给出完整可直接执行的代码
完整的前端安全实现:
完整的前端代码
/app/view/login/login.html
1 |
|
完整的控制器
app\controller\Index.php
1 |
|
完整的数据校验类
将name字段长度限制在15以内,password校验
app\validate\User.php
1 |
|
安全防护效果
成功验证
CSRF令牌防护
到此,本文结束,总结一下
前端安全措施
- 用户交互表单:基于Tailwind CSS的响应式表单,包含客户端必填验证
- 异步提交机制:使用Fetch API实现无刷新提交,提升用户体验
- 数据安全处理:
- 邮箱Base64编码传输
- 密码MD5哈希处理
- 动态盐值完整性验证
- 状态反馈机制:完整的加载状态、成功/错误提示
- CSRF集成:无缝集成后端令牌系统
后端防护体系
- CSRF防护:基于ThinkPHP的令牌生成与验证
- 动态盐值:时间戳基础的临时盐值生成
- 完整性验证:SHA256哈希完整性校验
- 请求时效:60秒请求超时机制
- 数据验证:严格的数据格式与长度验证
- 异常处理:统一的错误响应机制
安全威胁防护矩阵
| 攻击类型 | 防护措施 | 实现机制 |
|---|---|---|
| CSRF攻击 | Token验证 | 后端生成一次性令牌,前端携带验证 |
| 数据篡改 | 完整性哈希 | SHA256(核心数据+盐值)验证 |
| 重放攻击 | 时间戳校验 | 60秒请求有效期限制 |
| 明文泄露 | 数据编码 | Base64邮箱 + MD5密码哈希 |
| 参数缺失 | 必填验证 | 关键参数空值检测 |
| 信息泄露 | 异常封装 | 统一错误响应,避免敏感信息暴露 |
通过这套完整的前后端协同安全方案,有效提升了系统的安全性,一定程度上完善了交互逻辑,当然这还不够,在数据库层面我们仍然需要进行数据校验,确保数据库存储的是完整数据,未经过修改的数据,由于时间原因,项目暂时搁置,本次仍缺失的内容
- 更安全的数据签证(后端加密,数据库校验)
- 基于角色的验证(RABC原则)
- 基于中间件的认证防护(Kong)
如果不了解,可以看看下面的文章
中间件kong 以及konga安装部署方法
中间件认证的基础插件
加强密钥管理,避免敏感信息泄露
增强数据校验以及数据库存储数据的安全性
Gitea安装部署
Git 安全使用
JumpServer终端审计录像以及回访
Zabbix服务器监控









