在 python 中验证 StoreKit 2 事务 jwsRepresentation 的正确方法是什么?

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

从文档中并不清楚您实际上要做什么来验证服务器端 StoreKit 2 事务中的 jwsRepresentation 字符串。

来自 Apple App Store 通知 V2 的“signedPayload”似乎是相同的,但除了在设备上验证客户端之外,也没有关于实际验证的文档。

什么给予?我们用这个 JWS/JWT 做什么?

python swift jwt storekit
2个回答
5
投票
(免责声明:我是加密新手,所以如果我在整个过程中使用了错误的术语等,请检查我)

jwsRepresentation

中的JWS和Notification V2 JSON正文中的
signedPayload
都是JWT——您可以在
jwt.io上查看它。这项工作是验证 JWT 签名,并在您充分确信它确实来自 Apple 后提取有效负载。然后,有效负载本身包含可用于升级用户帐户等的信息。一旦数据可信,服务器端。

要验证 JWT,您需要找到 JWT 标头的

"x5c"

 集合中指定的 JWT 签名,验证证书链,然后验证签名是否确实来自 Apple。

第一步:从 Apple 加载众所周知的根证书和中间证书。

import requests from OpenSSL import crypto ROOT_CER_URL = "https://www.apple.com/certificateauthority/AppleRootCA-G3.cer" G6_CER_URL = "https://www.apple.com/certificateauthority/AppleWWDRCAG6.cer" root_cert_bytes: bytes = requests.get(ROOT_CER_URL).content root_cert = crypto.load_certificate(crypto.FILETYPE_ASN1, root_cert_bytes) g6_cert_bytes: bytes = requests.get(G6_CER_URL).content g6_cert = crypto.load_certificate(crypto.FILETYPE_ASN1, g6_cert_bytes)

第二步:从 JWT 标头中获取证书链

import jwt # PyJWT library # Get the signing keys out of the JWT header. The header will look like: # {"alg": "ES256", "x5c": ["...base64 cert...", "...base64 cert..."]} header = jwt.get_unverified_header(apple_jwt_string) provided_certificates: List[crypto.X509] = [] for cert_base64 in header['x5c']: cert_bytes = base64url_decode(cert_base64) cert = crypto.load_certificate(crypto.FILETYPE_ASN1, cert_bytes) provided_certificates.append(cert)

第三步:验证链是否如您所想——这可确保证书链由真正的 Apple 根证书和中间证书签名。

# First make sure these are the root & intermediate certs from Apple: assert provided_certificates[-2].digest('sha256') == g6_cert.digest('sha256') assert provided_certificates[-1].digest('sha256') == root_cert.digest('sha256') # Now validate that the cert chain is cryptographically legit: store = crypto.X509Store() store.add_cert(root_cert) store.add_cert(g6_cert) for cert in provided_certificates[:-2]: try: crypto.X509StoreContext(store, cert).verify_certificate() except crypto.X509StoreContextError: logging.error("Invalid certificate chain in JWT: %s", apple_jwt) return None store.add_cert(cert)

FINALLY:使用标头中现在受信任的证书加载并验证 JWT。

# Now that the cert is validated, we can use it to verify the actual signature # of the JWT. PyJWT does not understand this certificate if we pass it in, so # we have to get the cryptography library's version of the same key: cryptography_version_of_key = provided_certificates[0].get_pubkey().to_cryptography_key() try: return jwt.decode(apple_jwt, cryptography_version_of_key, algorithms=["ES256"]) except Exception: logging.exception("Problem validating Apple JWT") return None
瞧,您现在可以使用 App Store 中经过验证的 JWT 正文。

整个解决方案的要点:

https://gist.github.com/taylorhughes/3968575b40dd97f851f35892931ebf3e


0
投票
Apple 现在提供了

App Store 服务器库,支持多种不同语言(包括 Python)。

您仍然需要自行管理加载根证书,但这里有一个示例:

from functools import from appstoreserverlibrary.models.Environment import Environment from appstoreserverlibrary.signed_data_verifier import VerificationException, SignedDataVerifier @lru_cache(maxsize=None) def _load_apple_root_certificates(): # https://www.apple.com/certificateauthority/ certs_urls = [ "https://www.apple.com/appleca/AppleIncRootCertificate.cer", "https://www.apple.com/certificateauthority/AppleComputerRootCertificate.cer", "https://www.apple.com/certificateauthority/AppleRootCA-G2.cer", "https://www.apple.com/certificateauthority/AppleRootCA-G3.cer", ] return [requests.get(cert_url).content for cert_url in certs_urls] root_certificates = _load_apple_root_certificates() enable_online_checks = True bundle_id = "com.example" environment = Environment.SANDBOX app_apple_id = None # appAppleId must be provided for the Production environment signed_data_verifier = SignedDataVerifier(root_certificates, enable_online_checks, environment, bundle_id, app_apple_id) try: signed_notification = "ey.." payload = signed_data_verifier.verify_and_decode_notification(signed_notification) print(payload) except VerificationException as e: print(e)
    
© www.soinside.com 2019 - 2024. All rights reserved.