前言在前端开发中我们经常使用localStorage来临时存储页面间传递的数据比如列表页跳转详情页时把当前行数据存入本地存储。 但是localStorage的数据是明文存储用户打开浏览器开发者工具就可以随意修改里面的 JSON 内容造成页面拿到被篡改后的脏数据引发业务异常。本文提供一套前端数据签名校验方案在存入localStorage时对原始数据 密钥生成 SHA256 签名读取数据的时候使用同样算法重新计算签名进行比对。如果数据被人为修改签名不一致直接判定数据非法。说明本方案仅用于防止普通用户在控制台手动篡改 localStorage 数据不能做到高强度防破解。密钥 secret 写在前端 JS 内有经验的攻击者依然可以提取密钥伪造签名适合页面简单防护场景敏感业务必须后端校验。一、业务场景说明业务场景列表页面点击列表行跳转到详情页。 需求点击列表行排除箭头 img/.arrow 元素把当前行 data 存入 localStorage存入时生成签名data和sign一起打包存储详情页读取本地存储重新计算签名校验如果用户在开发者工具修改了 localStorage 里面 data 字段的任何内容签名校验失败拒绝使用这份数据。点击列表上的箭头图片时不触发跳转详情逻辑。依赖CryptoJS库用于 SHA256 哈希签名。二、完整代码实现列表页存储数据并生成签名跳转详情/** * 跳转详情页存储数据并生成签名 * param {Event} e 点击事件对象 * param {Object} data 需要传递到详情页的行数据 */ function target_detail(e, data) { // 判断点击的是否为箭头img/.arrow元素点击箭头不跳转 if (e.target.closest(img,.arrow)) { // 点击箭头直接return不执行跳转逻辑 return; } const secret my_secret_key_2026; // 签名密钥实际项目可自定义 const store_key user_info; // localStorage存储key // 1、将原始对象转为JSON字符串 const rawStr JSON.stringify(data); // 2、原始数据 密钥做SHA256哈希生成签名sign const sign CryptoJS.SHA256(rawStr secret).toString(); // 3、打包原始数据和签名 const storeVal JSON.stringify({ data, sign }); // 存入本地存储 localStorage.setItem(store_key, storeVal); // 跳转到详情页面 window.location.href ../html/detail.html; }详情页读取本地存储校验签名/** * 读取localStorage数据并校验签名防止数据被篡改 * returns {Object|Boolean} 校验通过返回原始data校验失败/无数据返回false */ function readData() { // 1. 从localStorage取出打包好的字符串 const str localStorage.getItem(user_info); if (!str) { console.log(后台数据为空); return false; } else { // 将字符串解析拆分出存储的数据data和签名sign const { data, sign } JSON.parse(str); const secret my_secret_key_2026; // 密钥必须和列表页保持一致 // 获取数据重新计算签名 const newSign CryptoJS.SHA256(JSON.stringify(data) secret).toString(); // 比对两次签名 if (newSign sign) { // 签名一致数据没有被篡改返回原始数据 return data; } else { // 签名不一致数据被修改过返回false console.log(数据签名校验失败数据已被篡改); return false; } } }页面引入 CryptoJSscript srchttps://cdn.jsdelivr.net/npm/crypto-js4.2.0/crypto-js.min.js/script三、代码分步解析3.1target_detail列表点击跳转函数if (e.target.closest(img,.arrow)) { return; }e.target.closest(img,.arrow)事件委托判断当点击的元素是图片或者.arrow箭头时直接 return不触发跳转详情逻辑。实现「点击列表空白区域跳转点击箭头不跳转」的分离效果。const rawStr JSON.stringify(data); const sign CryptoJS.SHA256(rawStr secret).toString();核心签名逻辑将 JS 对象转为 JSON 字符串原始字符串 密钥secret拼接进行 SHA256 哈希输出十六进制字符串作为签名 sign。只要data里面任意一个字段的值发生改变rawStr就会变化最终生成的sign签名完全不一样。const storeVal JSON.stringify({data, sign}); localStorage.setItem(store_key, storeVal);把data和sign打包成一个对象存入 localStorage。本地存储不再单纯存业务数据而是业务数据 校验签名一起保存。3.2readData详情页校验函数const { data, sign } JSON.parse(str); const newSign CryptoJS.SHA256(JSON.stringify(data) secret).toString(); if (newSign sign) { return data; }else{ return false; }读取流程取出存储字符串JSON 解析得到data和之前生成的sign使用完全相同的密钥和算法基于当前取出的data重新计算一遍签名得到newSign对比newSign和原始sign✅相等数据没有被篡改可以放心使用❌不相等用户在开发者工具修改过 localStorage 内 data数据不可信返回 false页面做拦截提示。四、防篡改原理演示原始存入 localStorage 示例内容{ data: {id:1,name:张三}, sign:4026d1812fxxxxxx }场景用户打开开发者工具手动修改name为李四。 当详情页读取数据JSON.stringify(data)结果发生变化重新计算出来的newSign和原来存储的sign不匹配校验直接失败页面拒绝使用这份篡改后的数据。⚠️注意不是加密是签名data 依然是明文保存在 localStorage用户依然可以看到 data 内容签名只能检测数据是否被改动不能隐藏原始数据。五、方案优缺点分析✅优点实现简单轻量不需要后端参与纯前端完成校验有效阻挡普通用户打开开发者工具随意修改 localStorage 内业务数据搭配前面写的页面禁用 F12、禁用右键代码可以进一步提高篡改门槛SHA256 单向哈希无法通过签名反推出密钥。❌缺点重点secret 密钥写在前端 JS 代码中攻击者可以通过查看源码、断点调试拿到密钥伪造合法签名localStorage 数据依旧明文可见只能防篡改不能隐藏数据只适合页面临时传参这种轻量化场景不能用于登录、权限、敏感核心业务JSON.stringify 序列化存在顺序问题如果对象 key 顺序改变字符串结果会变签名会校验失败可自行做 key 排序优化。六、优化改进方向优化 1对象 key 排序解决 JSON.stringify 顺序问题对象属性顺序不同JSON.stringify生成字符串不一样导致相同数据签名不一致。可以写一个方法把对象 key 排序后再序列化。function sortObjKeys(obj) { return JSON.stringify(obj, Object.keys(obj).sort()); } // 使用 const rawStr sortObjKeys(data);优化 2增加随机盐值每次存储随机 salt每次生成签名时生成随机 saltsalt 和 sign 一起存入 localStorage签名计算改为rawStr salt secret进一步提升伪造难度。优化 3校验失败统一弹窗提示在readData返回 false 时调用之前封装好的showError弹窗提示「数据非法或已被篡改」并跳转回列表页。七、常见误区澄清❌ 使用这个方案数据就安全了 ✅ 只能防篡改校验前端密钥暴露专业人员依旧可以伪造签名前端存储永远不可信。❌ 签名就是加密别人看不到 data 内容 ✅ data 依旧明文存储在 localStorage任何人打开 Application 面板都能查看签名只用来校验是否改动。❌ 可以用来保护用户登录凭证 ✅ 登录态、权限校验这类核心逻辑必须放在后端做签名 / 校验不能依赖前端本地签名。八、配套组合方案这套代码可以和前面三篇博客的代码组合形成一套完整前端页面防护体系页面禁用 F12、禁用右键菜单提高打开开发者工具门槛SHA256 前端密码哈希锁屏页面Fullscreen 全屏切换与状态监听本地存储数据 SHA256 签名防篡改本文整套防护只适合前端演示、内部轻量系统不能作为互联网生产环境安全方案。总结当使用 localStorage 做页面之间数据传递时很容易遇到用户通过开发者工具篡改本地存储数据的问题。我们可以借助 SHA256 哈希签名的思路存储业务数据同时附带签名读取的时候做签名比对检测数据是否被修改。 一定要记住边界前端签名只是增加篡改门槛无法做到绝对安全涉及敏感业务场景所有可信校验逻辑必须放在服务端。
企业数字化 ERP 产品动态
相关推荐
智能制造——2026 智慧工厂AI赋能MES应用方案 本 57 页 PPT 适配智能工厂、工业数字化咨询方案编制。结合智能制造相关政策与行业市场数据,基于 ISA‑95 国标体系,解析 MES 定位、11 大核心功能域、跨系统集成逻辑。 覆盖离散、流程、混合制造差异化落地策略,对比云端、本地、混合部署模式,梳理厂商选型维度、实施痛点误… · 2026/9/25 18:59:00
Skills火了,一篇带你看懂来龙去脉:从Rules、Commands到MCP与Subagents的配置骨架 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 18:58:18
无本体和后训练模式,正在逼着近百家数采厂转型和撤退。 01 数采厂,正在关键转折点上:一场主动的撤退
2026 年 8 月 28 日,多家媒体报道,北京首个人形机器人数据训练中心已停止运营。
这个中心 2025 年 3 月在石景山首钢园揭牌,占地约 3000 平方米,部署过 100 多… · 2026/9/25 19:27:09
MFC连接MySQL的ODBC实战:从驱动配置到避坑指南 简介:面向C桌面开发者的MySQL数据库访问实例,以MFC为界面框架,通过ODBC统一接口连接MySQL,适合正在学习数据库编程、准备课程设计或需要快速搭建MFCODBC数据访问模板的开发者参考。资源为RAR压缩包,共117个文件&#x… · 2026/9/25 19:27:09
PyTorch原生Faster R-CNN从零训练VOC数据集实战 1. 项目概述:为什么一个Faster R-CNN训练流程值得从头写透Faster R-CNN不是个新模型,但直到今天,它依然是工业界目标检测任务里绕不开的“教科书级标杆”。你可能在论文里见过它的结构图,在开源库中调用过现成权重,甚至… · 2026/9/25 19:27:03
Qt中SqliteCipher加密SQLite并跨库查询:多库ATTACH实践 简介:针对Qt环境下SQLite数据库加密与多库操作需求,这份配套实例完整演示了SQLiteCipher的集成与使用,适合需要为桌面应用增加数据安全能力的Qt开发者。资源共101个文件,压缩包约35.85MB,内容以动态库dll、C源码cpp、界… · 2026/9/25 19:27:03
学生体质健康管理系统:MySQL数据库设计实战与期末大作业完整指南 简介:这份资源是一套完整的数据库期末大作业方案,围绕‘学生体质健康管理系统’整合了可运行源码、数据库脚本、介绍PPT和设计报告,主要面向计算机、软件、大数据等专业学生,可用于课程设计、大作业答辩或毕业设计前期参考。压缩包… · 2026/9/25 19:26:56
Windows 10截图保存路径与管理全指南 1. Windows 10截图后文件“消失”的真相:不是丢了,是藏得比你想象的还深你按下Win PrtSc,屏幕一闪,听到那声熟悉的“咔嚓”快门音——心里一松:“截好了。”可翻遍桌面、文档、图片文件夹,甚至把整个C盘按… · 2026/9/25 19:26:44
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37