数据签名/摘要 (Data Hashing/Signing)动态化

将前端生成的"令牌"(即数据哈希或签名)做成动态的,是提高其安全性和有效性的一种常用手段。

静态哈希(仅对提交的数据本身做哈希)的主要弱点在于:

  1. 可预测性: 如果攻击者知道哈希算法和数据格式,他们可以在修改数据后,重新计算出对应的"正确"哈希值,从而绕过服务端的校验(前提是攻击者能控制前端 JS 执行)。
  2. 重放攻击 (Replay Attack): 攻击者可以截获一个合法的请求(包含数据和对应的静态哈希),然后在稍后原封不动地重新发送这个请求,服务端校验哈希仍然会通过(尽管这可能需要配合其他机制如 Nonce 来防范)。

通过引入动态元素到哈希计算的数据中,可以显著增加攻击者伪造或重用哈希的难度。

如何实现动态化?

核心思想是在计算哈希/签名时,不仅仅包含要提交的核心业务数据,还要加入一些每次请求都不同与当前上下文相关的动态信息。

以下是一些常用的动态元素:

  1. 时间戳 (Timestamp):

    • 做法: 在前端获取当前时间的毫秒级时间戳,将其包含在要哈希的数据字符串中。

      javascript 复制代码
      // 前端
      const data = { userId: 123, amount: 100 };
      const timestamp = Date.now().toString(); // 获取当前时间戳字符串
      const dataToHash = JSON.stringify(data) + "|" + timestamp; // 将数据和时间戳拼接
      const hash = sha256(dataToHash); // 计算哈希
      
      // 发送请求时带上 data, timestamp, hash
      // 例如放在请求头:
      // X-Data-Hash: hash
      // X-Request-Timestamp: timestamp
    • 服务端校验:

      1. 接收 data, timestamp, hash
      2. 检查 timestamp 是否在可接受的时间窗口内(例如,与服务器当前时间相差不超过几秒或几十秒),防止过旧的请求被重放。
      3. 完全相同 的方式拼接接收到的 datatimestamp
      4. 重新计算哈希。
      5. 比较计算出的哈希和接收到的 hash 是否一致。
    • 优点: 简单易实现,每次请求的哈希都不同。

    • 缺点: 客户端和服务器需要有大致同步的时间;如果攻击者能控制 JS,他们可以发送当前的 timestamp 和篡改后数据计算出的哈希。主要增加了重放攻击的难度。

  2. Nonce (Number used once - 随机数):

    • 做法:

      • 服务器生成: 服务器在加载页面或通过特定 API 预先提供一个一次性的随机字符串 (Nonce)。前端在计算哈希时包含这个 Nonce。
      • 前端生成 (不太推荐,除非服务器能有效跟踪): 前端生成一个足够随机且唯一的字符串。
      javascript 复制代码
      // 前端 (假设从服务器获取了 nonce)
      const data = { userId: 123, amount: 100 };
      const nonce = getNonceFromServer(); // 获取一次性随机数
      const dataToHash = JSON.stringify(data) + "|" + nonce;
      const hash = sha256(dataToHash);
      
      // 发送请求时带上 data, nonce, hash
    • 服务端校验:

      1. 接收 data, nonce, hash
      2. 验证 nonce 的有效性: 检查该 nonce 是否由服务器签发且从未使用过。使用过的 Nonce 应立即标记为无效。
      3. 拼接 datanonce,重新计算哈希。
      4. 比较哈希值。
    • 优点: 非常有效地防止重放攻击,因为每个 Nonce 只能用一次。

    • 缺点: 服务器需要生成、存储、验证和管理 Nonce 的状态,增加了服务端的复杂性。

  3. 结合密钥的 HMAC (Hash-based Message Authentication Code):

    • 做法: 这本身就是一种动态化的方式,因为它引入了一个密钥 (Secret Key) 。但如前所述,将密钥安全地存储在前端非常困难。如果要做,可以考虑:

      • 短期动态密钥: 服务器通过安全方式(例如在用户登录后,通过一个受保护的 API)下发一个有时效性的短生命周期密钥给前端,前端使用这个密钥计算 HMAC。密钥过期后需要重新获取。
      javascript 复制代码
      // 前端 (假设获取了 sessionKey)
      const data = { userId: 123, amount: 100 };
      const sessionKey = getSessionKey(); // 获取当前会话的短期密钥
      const dataString = JSON.stringify(data);
      const hmacSignature = hmacSha256(dataString, sessionKey); // 使用密钥计算 HMAC
      
      // 发送请求时带上 data, hmacSignature (可能还需要标识密钥版本/ID)
    • 服务端校验: 使用与前端相同的、对应当前会话/用户的密钥,对接收到的 data 计算 HMAC,并与接收到的 hmacSignature 比较。

    • 优点: 比简单哈希更难伪造,因为需要密钥。

    • 缺点: 前端密钥管理是核心难题。如果攻击者能拿到 JS 中的密钥,HMAC 依然可以被伪造。动态密钥增加了复杂性。

  4. 挑战-应答 (Challenge-Response):

    • 做法:
      1. 前端发起请求意图。
      2. 服务器生成一个随机的"挑战 (Challenge)"字符串,发送给前端。
      3. 前端将这个 challenge、要提交的 data(可能还有时间戳或 Nonce)一起进行哈希或签名计算。
      4. 前端将 datachallenge 和计算结果 response 发送给服务器。
    • 服务端校验: 服务器查找之前发送给该会话的 challenge,用相同方式计算预期 response,并与收到的 response 比较。
    • 优点: 增加了交互,使得每次请求的计算都依赖于服务器的动态输入。
    • 缺点: 增加了一次网络往返,流程更复杂。同样,如果 JS 被控制,攻击者可以正确响应挑战。

总结与建议:

  • 动态化是必要的: 相比静态哈希,引入动态元素(如时间戳或 Nonce)可以显著提高安全性,特别是防御重放攻击。
  • 时间戳 + 哈希: 实现简单,能有效防止旧请求重放,是常用的基础动态化方案。
  • Nonce + 哈希: 防重放效果最好,但增加了服务器状态管理的复杂性。
  • HMAC (带动态密钥): 理论上更安全,但前端密钥管理是巨大挑战,需要非常谨慎地设计密钥下发和轮换机制。
  • 核心限制不变: 无论如何动态化,只要哈希/签名计算过程完全在前端(且攻击者能控制 JS),攻击者总是有可能通过模拟计算过程来伪造有效的"令牌"。这些前端校验手段的主要作用是增加攻击难度提供信号,而不是提供绝对的安全保证。
  • 最终依赖: HTTPS 保证传输安全 + 严格的服务端验证(业务逻辑、权限、输入清理) 仍然是安全的基石。前端的动态哈希/签名应作为辅助增强手段。

选择哪种动态化方式取决于你的安全需求、对复杂性的接受程度以及服务端的实现能力。通常 时间戳 + 哈希 是一个不错的起点。

相关推荐
POLITE314 分钟前
Leetcode 238.除了自身以外数组的乘积 JavaScript (Day 7)
前端·javascript·leetcode
光影少年18 分钟前
AI前端开发需要会哪些及未来发展?
前端·人工智能·前端框架
Vincent_Vang30 分钟前
多态 、抽象类、抽象类和具体类的区别、抽象方法和具体方法的区别 以及 重载和重写的相同和不同之处
java·开发语言·前端·ide
菩提小狗32 分钟前
小迪安全_第4天:基础入门-30余种加密编码进制&Web&数据库&系统&代码&参数值|小迪安全笔记|网络安全|
前端·网络·数据库·笔记·安全·web安全
闲蛋小超人笑嘻嘻33 分钟前
非父子通信: provide和inject
前端·javascript·vue.js
止观止1 小时前
不止解构:深入掌握 ES6+ 对象与函数的高级语法糖
前端·javascript·es6
C_心欲无痕1 小时前
react - useTransition标记低优先级更新
前端·react.js·前端框架
捻tua馔...1 小时前
antd3的表单实现(HOC解决方案)
前端·javascript·react.js
支付宝体验科技1 小时前
支付宝 KJS Compose 动态化方案与架构设计
前端·客户端
AllinLin1 小时前
JS中的call apply bind全面解析
前端·javascript·vue.js