HarmonyOS掌上记账APP开发实践第65篇:JWS 收据验证与安全性 — 基于 JWSUtil 的支付凭证解码
JWS 收据验证与安全性 — 基于 JWSUtil 的支付凭证解码

文章简介
在移动支付场景中,客户端收到的支付凭证需要经过完整性和真实性验证,才能确保用户确实完成了支付。鸿蒙 IAP 使用 JWS(JSON Web Signature)作为支付收据格式,客户端需要将收据解码后发送到服务端进行验证。MoneyTrack 封装了 JWSUtil 工具类来处理 JWS 的解码过程,本文深入解析 JWS 格式、Base64 URL-safe 编解码、服务端验签及安全性考虑等技术细节。
核心知识点
1. JWS 解码验证流程
以下流程图展示了 JWS 收据从客户端接收到服务端验证的完整链路:
2. JWS 三部分结构的详细说明
JWS 格式遵循 RFC 7515 标准,由三个以点号(.)分隔的部分组成:header.payload.signature。
Header(头部):描述签名的算法和类型。典型内容为 {"alg":"RS256","typ":"JWS"},指明使用 RSA-SHA256 算法签名。客户端应解析此字段确认服务端使用的签名算法与预期一致。
Payload(载荷):包含实际的支付凭证数据,如订单 ID、商品 ID、购买时间、用户 ID 等。这是应用最关心的数据部分,需解码后提取订单信息发送给服务端进行业务验证。
Signature(签名):对 header.payload 的签名数据。服务端使用 AGC 提供的公钥进行验签,确保数据未被篡改。私钥由 AppGallery Connect 安全保管,客户端无法伪造。
// JWS 三段式解码
const jws: string[] = data.split('.');
let header = jws[0]; // 第一段:Header
let payload = jws[1]; // 第二段:Payload
let signature = jws[2]; // 第三段:Signature
if (jws.length < 3) { return ''; } // 格式不合法
3. util.Base64Helper 的完整 API
HarmonyOS 的 util.Base64Helper 提供了完整的 Base64 编解码能力,JWSUtil 借助此类完成 URL-safe 解码:
| API | 说明 | 参数类型 | 返回类型 |
|---|---|---|---|
encodeSync(src) |
标准 Base64 编码 | Uint8Array |
Uint8Array |
decodeSync(src) |
标准 Base64 解码 | Uint8Array |
Uint8Array |
encodeToStringSync(src) |
编码为字符串 | Uint8Array |
string |
JWS 使用 Base64 URL-safe 变体,与标准 Base64 的差异需手动转换:将 - 替换为 +、_ 替换为 /,并补充尾部 = 填充符:
const base64 = new util.Base64Helper();
const textDecoder = util.TextDecoder.create('utf-8', { ignoreBOM: true });
// URL-safe → 标准 Base64
const centerLineRegex: RegExp = new RegExp('-', 'g');
const underLineRegex: RegExp = new RegExp('_', 'g');
payload = payload.replace(centerLineRegex, '+').replace(underLineRegex, '/');
// 补充填充符
const pad = payload.length % 4;
if (pad) { payload += new Array(4 - pad + 1).join('='); }
// 解码
result = textDecoder.decodeToString(base64.decodeSync(payload));
4. 服务端验签说明
客户端的 JWS 解码仅用于提取收据内容,真正的签名验证必须在服务端完成。服务端验签流程如下:
- 客户端将解码后的 Payload(或原始 JWS 字符串)发送到服务端。
- 服务端使用 AppGallery Connect 提供的公钥,验证 JWS 签名的合法性。
- 验证通过后,服务端检查 Payload 中的
orderId、productId、purchaseTime等字段是否与预期一致。 - 服务端记录已验证的收据,防止重复使用同一收据激活多个设备。
// 服务端伪代码(Java)
PublicKey publicKey = getAGCPublicKey();
JWSVerifier verifier = new RSASSAVerifier(publicKey);
SignedJWT signedJWT = SignedJWT.parse(jwsString);
boolean isValid = signedJWT.verify(verifier);
5. 安全性考虑
防篡改:JWS 的签名机制确保任何对 Header 或 Payload 的篡改都会被验证环节发现。客户端解码后不应直接信任 Payload 内容,必须依赖服务端验签。
重放攻击防护:收据中包含 purchaseTime 和 orderId。服务端应记录已使用过的 orderId,拒绝重复的验证请求。同时建议检查 purchaseTime 与当前时间的偏差,拒绝超过 5 分钟的老收据。
传输安全:客户端向服务端传输收据时,必须通过 HTTPS 协议,防止中间人窃取收据内容后冒用。
项目代码案例
JWSUtil.ets 的 decodeJwsObj 方法
文件路径:components/membership/src/main/ets/util/JWSUtil.ets
public static decodeJwsObj(data: string): string {
const jws: string[] = data.split('.');
let result: string = '';
if (jws.length < 3) { return result; }
try {
const textDecoder = util.TextDecoder.create('utf-8', { ignoreBOM: true });
const base64 = new util.Base64Helper();
let payload = jws[1];
payload = payload.replace(new RegExp('-', 'g'), '+').replace(new RegExp('_', 'g'), '/');
const pad = payload.length % 4;
if (pad) { payload += new Array(4 - pad + 1).join('='); }
result = textDecoder.decodeToString(base64.decodeSync(payload));
} catch (err) {
hilog.error(0xFF00, TAG, `decodeJwsObj parse err: ${JSON.stringify(err)}`);
}
return result;
}
推荐参考文档
- JSON Web Signature (JWS) RFC 7515 标准
- HarmonyOS util.Base64Helper 文档
- HarmonyOS util.TextDecoder 文档
- @kit.PerformanceAnalysisKit hilog 日志 API
- OWASP 防重放攻击最佳实践
更多推荐



所有评论(0)