Nodejs 上的 App Store 服务器通知服务器端验证

问题描述 投票:0回答:1

我有一个使用应用内购买的 iOS 应用程序。

当订阅某些计划时,苹果会在我提供的 webhook 上发布请求

在服务器端我从苹果接收此数据:

{"signedPayload": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}

我无法找到适当的后端文档来验证此有效负载。

有人可以给我提供一些示例或文档或一个非常好的nodejs库,可以让我轻松解码并从这个签名的令牌中获取有价值的信息

ios in-app-purchase applepay
1个回答
0
投票

从令牌(例如您指定的令牌)收集有效负载的策略与密码学基础知识相冲突。首先,您可能已经注意到您的

signedPayload
(从现在起我将其称为“源”)是一个 Base64 编码的 JSON 对象
我假设您对 JWT 的性质有基本了解,所以我只会提醒您它们由三个部分组成:

  • 标头,包含类型和算法信息,
  • 有效负载部分,实际数据的所在地,
  • 验证签名。

解码数据的最简单方法是使用 Base64 解码器 使有效负载部分以纯文本形式可见。虽然这是一个完美工作的解决方案,并且通常用于大多数非关键应用程序,但它不会检查有效负载的完整性,也不会验证源是否由 Apple 签名,这允许黑暗角色伪造有效负载,以便他们可以包含任何数据。更安全的解决方案是执行完整的 JWT 验证。可以通过以下步骤来实现:

  • 从源“标头”部分找到密钥 ID,
  • 从其 API 端点获取苹果公钥列表。响应可能包含多个密钥,程序必须选择与源具有相同
    kid
    (密钥 ID)的密钥,
  • 使用 JWT 库验证源完整性并解码有效负载。

你问了 NodeJS,代码如下:

const jwt = require("jsonwebtoken");
const axios = require("axios");
const jwkToPem = require("jwk-to-pem");

const jwksUrl = "https://appleid.apple.com/auth/keys"

async function getPublicKey(kid) {
    const res = (await axios.get(jwksUrl)).data.keys;
    const appleKey = res.find(key => key.kid == kid);

    return appleKey;
}

async function verifyJWT(signedPayload) {
    try {

        const header = jwt.decode(signedPayload, { complete: true }).header;

        const publicKey = await getPublicKey(header.kid);

        if (!publicKey) {
            throw new Error(`No matching key found for kid: ${kid}`);
        } else {
            console.log("Found matching key:");
            console.log(publicKey);
        }

        const pem = jwkToPem(publicKey)

        const decoded = jwt.verify(signedPayload, pem, { algorithms: ['RS256'] });
        return decoded;
        
    } catch (err) {
        console.error('Error verifying Apple JWT:', err);
        throw err;
    }
}

const signedPayload = "your signed payload here"

verifyJWT(signedPayload)
    .then(decoded => {
        console.log('Verified and Decoded Payload:', decoded);
    })
    .catch(err => {
        console.error('Verification failed:', err);
    });
© www.soinside.com 2019 - 2024. All rights reserved.