在后端验证 Apple StoreKit2 应用内购买收据 jwsRepresentation(节点理想情况下,但一切正常)

Validate Apple StoreKit2 in-app purchase receipt jwsRepresentation in backend (node ideally, but anything works)

如何在 Node 后端验证来自 StoreKit2 的应用内购买 JWS 表示?

解码有效负载很容易,但我在任何地方都找不到 Apple 用来签署这些 JWS/JWTs 的 public 密钥。在我使用 JWT 的任何其他时间,您只需使用节点 jsonwebtoken 库并传入签名者 public 密钥或共享密钥,配置或从 JWK 获取。

我可以使用 node-jose j.JWS.createVerify().verify(jwsString, {allowEmbeddedKey: true}).then(r => obj = r) 轻松解码 JWS,这给了我一个像这样的对象:

 {
  protected: [ 'alg', 'x5c' ],
  header: {
    alg: 'ES256',
    x5c: [
      'MIIEMDueU3...',
      'MII..., 
'MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwSQXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0...'  
    ]
  },
  payload: <Buffer 7b 22 74 72 61 6e 73 61 63 74 69 6f 6e 49 64 22 3a 22 31 30 30 30 30 30 30 38 38 36 39 31 32 38 39 30 22 2c 22 6f 72 69 67 69 6e 61 6c 54 72 61 6e 73 ... 420 more bytes>,
  signature: <Buffer f8 85 65 79 a1 dc 74 dd 90 80 0a a4 08 85 30 e7 22 80 4c 20 66 09 0b 84 fc f4 e5 57 53 da d5 6f 13 c6 8f 56 e8 29 67 5c 95 a6 27 33 47 1e fe e9 6e 41 ... 14 more bytes>,
  key: JWKBaseKeyObject {
    keystore: JWKStore {},
    length: 256,
    kty: 'EC',
    kid: 'Prod ECC Mac App Store and iTunes Store Receipt Signing',
    use: '',
    alg: ''
  }
}

并且很容易 JSON.parse 有效负载并获取我想要的数据。但是,我如何使用 x5c 字段

中的证书链来验证其真实性

谢谢!

JWS x5c header 参数包含用于签署和验证 JWS 的整个证书链。无需获取任何其他证书或密钥。

RFC指定用于签署JWS的public密钥对应的证书必须是第一个证书。

您可以从此证书中提取 public 密钥并使用它来验证 JWS 签名。 this answer

中对此有一些指导

StoreKit2 的一大改进是您不再需要使用服务器来安全地验证应用内购买交易。

Apple 的 WWDC 2021 session on StoreKit2 描述了 JWS 的内容,还展示了如何在设备上验证 JWS 是为该设备实际生成的

但是,如果您确实想在服务器上验证交易怎么办?由于 x5c 声明包含证书链,攻击者可以使用他们自己的证书签署伪造的 JWS,并将该证书包含在 x5c 声明中。

答案是让您的应用将原始交易 ID 连同您需要的任何其他信息(例如用户的帐户标识符)发送到您的服务器。然后,您的服务器可以 request the corresponding JWS from Apple 并验证返回的 JWS 的签名。

由于 JWS 是通过您的服务器代码从 Apple 获取的,因此可以确定它不是欺骗性的 JWS。

如果可能,请在您的购买请求中包含一个 appAccountToken 并根据用户对您的服务器的身份验证来确定预期的令牌值,或者(效果较差)让您的应用在提供原始令牌时提供令牌交易编号。然后,您可以验证 JWS 中的令牌值是否与预期值匹配。这使得攻击者更难重播其他购买事件。

终于明白了。事实证明,我们需要一个“硬编码”证书来进行检查。

Apple 拥有 their website 所需的证书。您已经下载了根证书(因为这是签署整个链的证书),但您也可以获得中间证书。

下载后将其转换为 .pem:

 $ openssl x509 -inform der -in apple_root.cer -out apple_root.pem

那么您需要做的就是根据 JWS 中的内容验证它们:

if (openssl_x509_verify($jws_root_cert, $downloaded_apple_root_cert) == 1){
    //valid
}

希望这对其他人有帮助!