处理Apple App Store服务器通知时x5c证书链解码与验签问题
Apple App Store 服务器到服务器通知V2验签指南
现有实现进展校验
你梳理的大部分逻辑正确,有2个容易踩坑的细节需要修正:
- 通知接收与字段提取逻辑正确:V2版本通知以JSON格式推送,顶层
signedPayload字段为标准JWT结构,按.分割可得到Header、Payload、Signature三段内容;注意三段内容均为base64url编码,解码时需要先把-替换为+、_替换为/,补全末尾缺失的=padding后再做base64解码,不要直接用普通base64逻辑解码。 - Header解析逻辑基本正确:解码后得到的JSON固定包含
alg(固定值为ES256)、x5c两个字段;注意:x5c字段是JSON数组类型,包含3个base64编码的证书字符串,顺序为[叶子实体证书, WWDR中间证书, Apple根证书],并非逗号分隔的单字符串,不要手动按逗号拆分证书内容。 - Payload处理原则正确:Payload解码后的业务字段可对照官方字段说明解析,必须完成全链路签名校验后才能执行业务逻辑,不可提前信任Payload内容,Signature段需要留存用于最终验签比对。
- 证书基础识别正确:x5c数组第3位为Apple Root CA-G3根证书,第2位为Apple WWDRCA G6中间证书,你使用的cer转pem命令可正常工作:
openssl x509 -inform der -in AppleRootCA-G3.cer -outform pem -out AppleRootCA-G3.pem
提前本地预置官方渠道下载的根证书、中间证书用于比对是正确的实践。 - 你目前完成的证书issuer/subject匹配校验,只是证书链校验的必要非充分条件,还未完成完整合法性校验。
可使用以下命令查看证书的issuer、subject等文本信息:openssl x509 -text -in AppleRootCA-G3.pemopenssl x509 -text -in AppleWWDRCAG6.pem
核心问题解答
完整x5c证书链合法性校验流程
完成issuer/subject匹配后,还需要依次完成以下校验,全部通过才算证书链合法:
- 证书一致性校验:将x5c数组中取出的中间证书、根证书,分别和本地预置的官方同版本证书做二进制内容比对,完全一致才可进入下一步,避免攻击者伪造同issuer/subject的恶意证书绕过校验。
- 有效期校验:分别校验三张证书的
notBefore、notAfter时间,确认当前处理通知的时间落在三张证书的有效周期内,拒绝过期、未生效的证书。 - 层级签名校验:用根证书的公钥校验中间证书的签名,确认中间证书确实由对应根证书签发;再用中间证书的公钥校验叶子实体证书的签名,确认叶子证书由对应中间证书签发;最后校验根证书的自签名可被自身公钥验证通过。
- 叶子证书用途校验:校验叶子证书的扩展密钥用途(EKU)字段,确认其包含OID
1.2.840.113635.100.6.11(App Store服务器通知签名专用标识),防止攻击者复用Apple签发的其他用途证书伪造通知。
核心安全提示:绝对不要直接信任请求携带的根证书,必须和本地预置的官方根证书做一致性校验,这是防御证书链伪造的核心环节。
ES256 JWT签名验签流程
证书链校验全部通过后,按以下步骤完成最终签名比对:
- 从校验通过的叶子实体证书中提取EC P-256曲线公钥,这是ES256算法验签使用的公钥。
- 构造签名基串:直接取
signedPayload按.分割后的前两段原始字符串,用.拼接,即[Header原始串].[Payload原始串],不要对内容做任何重新编码、转义操作,否则会导致签名基串不匹配。 - 用ES256算法,以上述提取的公钥校验签名基串的签名,和拆分得到的Signature段解码后的内容做比对,比对一致则JWT签名有效。
- 格式注意:JWT规范中ES256的签名为IEEE P1363格式(r、s值各32字节直接拼接),部分加密库默认要求ASN.1 DER编码格式的签名,需要提前做格式转换,否则会出现合法签名验签失败的问题。
共享密钥使用说明
- V2版本
signedPayload的整个验签流程完全不需要使用App Store Connect中配置的共享密钥:共享密钥仅用于V1版本通知验签、旧版收据验证接口的请求鉴权,和V2通知的JWT验签逻辑无关,不要将共享密钥传入验签流程。 - 共享密钥不参与V2通知的任何校验环节,验签流程仅依赖x5c证书链和JWT本身的内容即可完成。
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

