新闻中心

解决Webhook签名验证中Python与TypeScript差异的实用指南

2025-11-15
浏览次数:
返回列表

解决webhook签名验证中python与typescript差异的实用指南

本文旨在解决在Webhook签名验证过程中,Python与TypeScript实现之间出现的差异问题。通过详细分析两种语言在JSON序列化时的不同行为,提供了一套可靠的TypeScript解决方案,确保签名验证的一致性和准确性。该方案通过规范化JSON字符串格式,消除了因空格差异导致的验证失败问题,从而保证了Webhook通信的安全性和可靠性。

在开发涉及Webhook的应用时,确保接收到的数据确实来自可信来源至关重要。Webhook签名验证是一种常见的安全措施,它通过使用共享密钥对请求内容进行签名,并在接收端验证签名,从而防止恶意篡改。然而,在跨语言环境中实现签名验证时,可能会遇到一些意想不到的问题,例如Python和TypeScript在处理JSON序列化时的差异。

问题根源:JSON序列化格式的差异

Python的json.dumps()方法在默认情况下会生成紧凑的JSON字符串,不包含额外的空格。而TypeScript中使用JSON.stringify()在没有指定参数的情况下也会生成紧凑的JSON字符串。但是,如果格式化JSON(例如为了方便调试),可能会引入空格,导致生成的签名与预期不符。即使没有格式化,不同的JSON序列化库也可能在空格处理上存在细微差异。

解决方案:规范化JSON字符串格式

为了解决这个问题,我们需要在TypeScript中规范化JSON字符串的格式,使其与Python生成的格式保持一致。一种有效的方法是使用一系列的字符串替换操作,移除或调整JSON字符串中的空格。

以下代码展示了如何使用Ramda库中的pipe和replace函数,创建一个名为toJSONWithSpaces的函数,该函数可以规范化JSON字符串的格式:

Visla Visla

AI视频生成器,快速轻松地将您的想法转化为视觉上令人惊叹的视频。

Visla 100 查看详情 Visla
import { pipe, replace } from 'ramda';

export const toJSONWithSpaces = pipe(
  (object: unknown) => JSON.stringify(object, null, 1), // stringify with line-breaks and indents
  replace(/\n +/gm, ' '), // replace line breaks and following spaces with a single space
  replace(/:\s/g, ': '), // ensure a space after colon
  replace(/{\s/g, '{'), // remove space after opening brace
  replace(/\s}/g, '}'), // remove space before closing brace
  replace(/\[\s/g, '['), // remove space after opening bracket
  replace(/\s]/g, ']'), // remove space before closing bracket
  replace(/,\s/g, ', '), // ensure a space after comma
);

这个函数首先使用JSON.stringify(object, null, 1)将对象转换为带有换行符和缩进的JSON字符串。然后,它使用一系列的正则表达式替换操作来移除或调整空格,以确保JSON字符串的格式与Python生成的格式一致。

集成到签名验证函数中

接下来,我们需要将toJSONWithSpaces函数集成到签名验证函数中。以下是一个修改后的verifyCloseSignature函数,它使用toJSONWithSpaces函数来规范化payload:

import { toJSONWithSpaces } from './json-formatter'; // 假设 toJSONWithSpaces 函数在 json-formatter.ts 文件中
import * as crypto from 'crypto';

export function verifyCloseSignature(
  request: Request,
  key: string,
  payload: any,
) {
  const headers = request.headers;

  const timestamp = headers.get('close-sig-timestamp');
  const providedSignature = headers.get('close-sig-hash');

  if (!timestamp) {
    throw new Error('[verifyCloseSignature] Required timestamp header missing');
  }

  if (!providedSignature) {
    throw new Error('[verifyCloseSignature] Required signature header missing');
  }

  const hmac = crypto.createHmac('sha256', Buffer.from(key, 'hex'));
  const cleanedPayload = toJSONWithSpaces(payload);
  hmac.update(timestamp + cleanedPayload);
  const calculatedSignature = hmac.digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(providedSignature, 'hex'),
    Buffer.from(calculatedSignature, 'hex'),
  );
}

在这个修改后的函数中,我们首先使用toJSONWithSpaces(payload)来规范化payload,然后再将其用于HMAC计算。

注意事项

  • 依赖管理: 确保安装了ramda库,可以通过运行npm install ramda或yarn add ramda来安装。
  • 密钥格式: 确认密钥是以十六进制字符串的形式提供的,并且在TypeScript中使用Buffer.from(key, 'hex')正确地将其转换为Buffer。
  • 时间戳: 确保时间戳的格式在Python和TypeScript中一致。通常,时间戳应该是一个整数或字符串,表示自Epoch以来的秒数。
  • Content-Type: 确保请求头的 Content-Type 设置为 application/json。

总结

通过规范化JSON字符串的格式,我们可以解决在Webhook签名验证过程中Python和TypeScript实现之间的差异问题。这种方法可以确保签名验证的一致性和准确性,从而提高Webhook通信的安全性和可靠性。在实际应用中,建议编写单元测试来验证签名验证函数的正确性,并定期审查和更新代码,以应对潜在的安全风险。

以上就是解决Webhook签名验证中Python与TypeScript差异的实用指南的详细内容,更多请关注其它相关文章!


# 转换为  # 海口网站建设的重要步骤  # 南京营销推广厂家  # 永川区品牌网站建设公司  # 邢台网站推广引流  # 徐元seo图片  # 商洛抖音seo运营公司  # 宜昌平台网站建设  # seo网站优化自学  # 大兴营销网络推广  # 网站平台建立与推广  # 情况下  # 您的  # 复用  # 过程中  # 移除  # python  # 将其  # 序列化  # 是一个  # cryp  # red  # win  # amd  # mac  # app  # npm  # typescript  # 正则表达式  # json  # js 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: J*aScript数组对象转换:按指定键分组与值收集  Yandex官网免登录入口_俄罗斯Yandex搜索引擎一键访问  Go语言中动态执行代码字符串的策略与实践  2026春节假期票务安排_2026春节放假购票指南  mysql如何设置表访问权限_mysql表访问权限配置  PySpark中高效提取字符串右侧可变长度数字:使用regexp_extract  抓大鹅解压小游戏 抓大鹅摸鱼解压入口  《噬血代码2》新预告片发布 展示游戏剧情  《燕云十六声》两周内达九百万玩家!位居畅销榜第五  UC浏览器官网入口2025最新 UC浏览器网页版正式地址  腾讯视频怎么使用多账号家庭管理_腾讯视频家庭多账号统一管理与权限分配教程  Yandex搜索引擎官网入口_俄罗斯Yandex免登录一键直达  sublime如何优雅地处理行尾空格_sublime自动清理多余空白字符配置  深入理解字体排版:Adobe光学字偶距与CSS字偶距的差异与实现  Google翻译怎么语音输入_Google翻译语音输入功能使用与设置方法  PDF怎么合并PDF并保持格式_PDF合并文件保持排版教程  如何在网页中实现特定地点的随机图片展示  从J*aScript对象中精确提取指定属性的教程  正确连接J*aScript到HTML实现可点击图片与自定义事件处理  sublime侧边栏怎么增强功能_SideBarEnhancements for sublime安装与配置  向日葵客户端怎么进行远程CentOS控制_向日葵客户端远程CentOS控制操作教程  在J*a中如何开发简易仓库管理与库存统计_仓库管理库存统计项目实战解析  如何在CSS中使用浮动制作导航栏_float实现水平菜单  c++ dfs和bfs代码 c++深度广度优先搜索算法  淘宝支付提示失败如何解决 淘宝支付流程优化方法  J*aScript DOM操作:高效清空列表元素的策略与实践  如何高效处理PHP中的Excel数据导入导出?PortPHP/Spreadsheet助你轻松搞定!  京东单号查询入口_京东快递订单追踪入口  composer的"require-dev"部分是用来做什么的?  俄罗斯Yandex搜索引擎入口_Yandex官网免登录一键访问  Win11蓝牙耳机断连怎么解决 Win11蓝牙设置重新配对与驱动更新【技巧】  AO3镜像入口大全 AO3网页版内容访问全集  NVIDIA股价11月重挫12%:下月有望好转 但难回5万亿美元巅峰  C++编译期如何执行复杂计算_C++模板元编程(TMP)技巧与应用  照顾宝贝2小游戏点击立即在线玩  sublime怎么覆盖插件的默认快捷键_sublime快捷键优先级与设置  Win11怎么开启省电模式_Win11电池节电模式自动开启  文心一言怎样用批量生成做多版文案_文心一言用批量生成做多版文案【批量创作】  Golang如何使用new_Go new分配内存机制讲解  Lar*el 递归关系中排除指定分支的教程  天眼查怎么看公司融资情况 天眼查企业融资历史查询步骤【攻略】  AO3最新镜像入口 Archive of Our Own官方平台访问  J*aScript map 迭代中检测空数组元素的有效方法  解决 Vaadin 8 中大文件音频播放与定位时出现的 IOException  Lar*el Excel导入时生成自定义递增ID的策略与实践  汽水音乐在线解析 汽水音乐在线解析入口  AO3最新入口2025公告_AO3中文官网合集  《北京人工智能产业白皮书(2025)》发布:全年核心产值预计突破 4500 亿元  漫蛙2网页版漫画入口 漫蛙漫画在线官方登录  HTML元素状态管理:根据DIV内容动态启用/禁用按钮 

搜索