gpt4 book ai didi

ios - 没有/verifyReceipt 请求的后端 iOS iap 收据验证

转载 作者:技术小花猫 更新时间:2023-10-29 11:06:00 25 4
gpt4 key购买 nike

我想在我的后端代码中验证 iOS 应用内购买收据。

Apple 使用外部/verifyReceipt 请求来执行此操作的设计决定非常愚蠢:它会导致延迟并增加网络错误处理的复杂性。更重要的是,收据中的数据看起来可以通过公钥验证。

在对收据的 signature 字段进行一些分析后,它似乎包含一个 PK 验证的 SHA1 哈希:

<?php
$sig="ApxQMks+KAE0riYtKjNNwhNeuGQ6R98X223zCh60s9m8wloydP3sCceQdzrCwd/3N1L+dlefT7ZJUiquCEsDAo+Rh54eSovcKEk+2RZyoP/zRQHgTF81kYBIbkFCADhj6kzJVr1rYsRXKpOJk6qWMYPz+a90XJfGtnIDuHlRb4V5AAADVzCCA1MwggI7oAMCAQICCGUUkU3ZWAS1MA0GCSqGSIb3DQEBBQUAMH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAwwqQXBwbGUgaVR1bmVzIFN0b3JlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA5MDYxNTIyMDU1NloXDTE0MDYxNDIyMDU1NlowZDEjMCEGA1UEAwwaUHVyY2hhc2VSZWNlaXB0Q2VydGlmaWNhdGUxGzAZBgNVBAsMEkFwcGxlIGlUdW5lcyBTdG9yZTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMrRjF2ct4IrSdiTChaI0g8pwv/cmHs8p/RwV/rt/91XKVhNl4XIBimKjQQNfgHsDs6yju++DrKJE7uKsphMddKYfFE5rGXsAdBEjBwRIxexTevx3HLEFGAt1moKx509dhxtiIdDgJv2YaVs49B0uJvNdy6SMqNNLHsDLzDS9oZHAgMBAAGjcjBwMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUNh3o4p2C0gEYtTJrDtdDC5FYQzowDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBSpg4PyGUjFPhJXCBTMzaN+mV8k9TAQBgoqhkiG92NkBgUBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEAEaSbPjtmN4C/IB3QEpK32RxacCDXdVXAeVReS5FaZxc+t88pQP93BiAxvdW/3eTSMGY5FbeAYL3etqP5gm8wrFojX0ikyVRStQ+/AQ0KEjtqB07kLs9QUe8czR8UGfdM1EumV/UgvDd4NwNYxLQMg4WTQfgkQQVy8GXZwVHgbE/UC6Y7053pGXBk51NPM3woxhd3gSRLvXj+loHsStcTEqe9pBDpmG5+sk4tw+GK3GMeEN5/+e1QT9np/Kl1nj+aBw7C0xsy0bFnaAd1cSS6xdory/CUvM6gtKsmnOOdqTesbp0bs8sn6Wqs0C9dgcxRHuOMZ2tm8npLUm7argOSzQ==";

file_put_contents('sig', substr(base64_decode($sig),1,128));
file_put_contents('cert.der', substr(base64_decode($sig),133));

# show certificate
echo `openssl x509 -in cert.der -inform der -noout -text` . "\n\n";

# convert to pem
`openssl x509 -in cert.der -inform der -out cert.pem`;

echo "signature:\n";
echo `openssl rsautl -in sig -verify -asn1parse -inkey cert.pem -certin`;
echo "\n\n";

输出:

Certificate:
Data:
Version: 3 (0x2)
Serial Number:
65:14:91:4d:d9:58:04:b5
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=Apple Inc., OU=Apple Certification Authority, CN=Apple iTunes Store Certification Authority
Validity
Not Before: Jun 15 22:05:56 2009 GMT
Not After : Jun 14 22:05:56 2014 GMT
Subject: CN=PurchaseReceiptCertificate, OU=Apple iTunes Store, O=Apple Inc., C=US
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:ca:d1:8c:5d:9c:b7:82:2b:49:d8:93:0a:16:88:
d2:0f:29:c2:ff:dc:98:7b:3c:a7:f4:70:57:fa:ed:
ff:dd:57:29:58:4d:97:85:c8:06:29:8a:8d:04:0d:
7e:01:ec:0e:ce:b2:8e:ef:be:0e:b2:89:13:bb:8a:
b2:98:4c:75:d2:98:7c:51:39:ac:65:ec:01:d0:44:
8c:1c:11:23:17:b1:4d:eb:f1:dc:72:c4:14:60:2d:
d6:6a:0a:c7:9d:3d:76:1c:6d:88:87:43:80:9b:f6:
61:a5:6c:e3:d0:74:b8:9b:cd:77:2e:92:32:a3:4d:
2c:7b:03:2f:30:d2:f6:86:47
Exponent: 65537 (0x10001)
--- cut ---

signature:
0:d=0 hl=2 l= 33 cons: SEQUENCE
2:d=1 hl=2 l= 9 cons: SEQUENCE
4:d=2 hl=2 l= 5 prim: OBJECT :sha1
11:d=2 hl=2 l= 0 prim: NULL
13:d=1 hl=2 l= 20 prim: OCTET STRING
0000 - b7 ef f1 9e 01 2a dd 26-09 38 cd ce 63 5b b1 32 .....*.&.8..c[.2
0010 - 88 51 17 0a .Q..

现在的问题是,这是哪些数据是散列。以上包含此收据的实际签名:

{
"signature" = "ApxQMks+KAE0riYtKjNNwhNeuGQ6R98X223zCh60s9m8wloydP3sCceQdzrCwd/3N1L+dlefT7ZJUiquCEsDAo+Rh54eSovcKEk+2RZyoP/zRQHgTF81kYBIbkFCADhj6kzJVr1rYsRXKpOJk6qWMYPz+a90XJfGtnIDuHlRb4V5AAADVzCCA1MwggI7oAMCAQICCGUUkU3ZWAS1MA0GCSqGSIb3DQEBBQUAMH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAwwqQXBwbGUgaVR1bmVzIFN0b3JlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA5MDYxNTIyMDU1NloXDTE0MDYxNDIyMDU1NlowZDEjMCEGA1UEAwwaUHVyY2hhc2VSZWNlaXB0Q2VydGlmaWNhdGUxGzAZBgNVBAsMEkFwcGxlIGlUdW5lcyBTdG9yZTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMrRjF2ct4IrSdiTChaI0g8pwv/cmHs8p/RwV/rt/91XKVhNl4XIBimKjQQNfgHsDs6yju++DrKJE7uKsphMddKYfFE5rGXsAdBEjBwRIxexTevx3HLEFGAt1moKx509dhxtiIdDgJv2YaVs49B0uJvNdy6SMqNNLHsDLzDS9oZHAgMBAAGjcjBwMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUNh3o4p2C0gEYtTJrDtdDC5FYQzowDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBSpg4PyGUjFPhJXCBTMzaN+mV8k9TAQBgoqhkiG92NkBgUBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEAEaSbPjtmN4C/IB3QEpK32RxacCDXdVXAeVReS5FaZxc+t88pQP93BiAxvdW/3eTSMGY5FbeAYL3etqP5gm8wrFojX0ikyVRStQ+/AQ0KEjtqB07kLs9QUe8czR8UGfdM1EumV/UgvDd4NwNYxLQMg4WTQfgkQQVy8GXZwVHgbE/UC6Y7053pGXBk51NPM3woxhd3gSRLvXj+loHsStcTEqe9pBDpmG5+sk4tw+GK3GMeEN5/+e1QT9np/Kl1nj+aBw7C0xsy0bFnaAd1cSS6xdory/CUvM6gtKsmnOOdqTesbp0bs8sn6Wqs0C9dgcxRHuOMZ2tm8npLUm7argOSzQ==";
"purchase-info" = "ewoJIm9yaWdpbmFsLXB1cmNoYXNlLWRhdGUtcHN0IiA9ICIyMDE0LTAxLTI3IDA0OjUwOjU2IEFtZXJpY2EvTG9zX0FuZ2VsZXMiOwoJInB1cmNoYXNlLWRhdGUtbXMiID0gIjEzOTA4MjcwNTYxNzciOwoJInVuaXF1ZS1pZGVudGlmaWVyIiA9ICJiMTUxOTczZThjYzY3ZGRlMzkwNzhiZDAwMGU4N2U3MjNiYjE0M2U1IjsKCSJvcmlnaW5hbC10cmFuc2FjdGlvbi1pZCIgPSAiMTAwMDAwMDA5OTcwODE1MCI7CgkiYnZycyIgPSAiMS4wLjciOwoJImFwcC1pdGVtLWlkIiA9ICI3MTE0MTEzMTciOwoJInRyYW5zYWN0aW9uLWlkIiA9ICIxMDAwMDAwMDk5NzA4MTUwIjsKCSJxdWFudGl0eSIgPSAiMSI7Cgkib3JpZ2luYWwtcHVyY2hhc2UtZGF0ZS1tcyIgPSAiMTM5MDgyNzA1NjE3NyI7CgkidW5pcXVlLXZlbmRvci1pZGVudGlmaWVyIiA9ICJCNjNBRTVFQy02MjBCLTQxMkEtQjE5NC03NUI3MDU3Mjk4M0MiOwoJIml0ZW0taWQiID0gIjc3NTg5MTg5MiI7CgkidmVyc2lvbi1leHRlcm5hbC1pZGVudGlmaWVyIiA9ICIxNzU5NTMxMzgiOwoJInByb2R1Y3QtaWQiID0gImNvbS5pbnRvbXlsaWZlLmNyZWRpdHMyNSI7CgkicHVyY2hhc2UtZGF0ZSIgPSAiMjAxNC0wMS0yNyAxMjo1MDo1NiBFdGMvR01UIjsKCSJvcmlnaW5hbC1wdXJjaGFzZS1kYXRlIiA9ICIyMDE0LTAxLTI3IDEyOjUwOjU2IEV0Yy9HTVQiOwoJImJpZCIgPSAiY29tLmludG9teWxpZmUuaW9zIjsKCSJwdXJjaGFzZS1kYXRlLXBzdCIgPSAiMjAxNC0wMS0yNyAwNDo1MDo1NiBBbWVyaWNhL0xvc19BbmdlbGVzIjsKfQ==";
"environment" = "Sandbox";
"pod" = "100";
"signing-status" = "0";
}

或者,在 base64 中:

$receipt="ewoJInNpZ25hdHVyZSIgPSAiQXB4UU1rcytLQUUwcmlZdEtqTk53aE5ldUdRNlI5OFgyMjN6Q2g2MHM5bTh3bG95ZFAzc0NjZVFkenJDd2QvM04xTCtkbGVmVDdaSlVpcXVDRXNEQW8rUmg1NGVTb3ZjS0VrKzJSWnlvUC96UlFIZ1RGODFrWUJJYmtGQ0FEaGo2a3pKVnIxcllzUlhLcE9KazZxV01ZUHorYTkwWEpmR3RuSUR1SGxSYjRWNUFBQURWekNDQTFNd2dnSTdvQU1DQVFJQ0NHVVVrVTNaV0FTMU1BMEdDU3FHU0liM0RRRUJCUVVBTUg4eEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURXpNREVHQTFVRUF3d3FRWEJ3YkdVZ2FWUjFibVZ6SUZOMGIzSmxJRU5sY25ScFptbGpZWFJwYjI0Z1FYVjBhRzl5YVhSNU1CNFhEVEE1TURZeE5USXlNRFUxTmxvWERURTBNRFl4TkRJeU1EVTFObG93WkRFak1DRUdBMVVFQXd3YVVIVnlZMmhoYzJWU1pXTmxhWEIwUTJWeWRHbG1hV05oZEdVeEd6QVpCZ05WQkFzTUVrRndjR3hsSUdsVWRXNWxjeUJUZEc5eVpURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd2daOHdEUVlKS29aSWh2Y05BUUVCQlFBRGdZMEFNSUdKQW9HQkFNclJqRjJjdDRJclNkaVRDaGFJMGc4cHd2L2NtSHM4cC9Sd1YvcnQvOTFYS1ZoTmw0WElCaW1LalFRTmZnSHNEczZ5anUrK0RyS0pFN3VLc3BoTWRkS1lmRkU1ckdYc0FkQkVqQndSSXhleFRldngzSExFRkdBdDFtb0t4NTA5ZGh4dGlJZERnSnYyWWFWczQ5QjB1SnZOZHk2U01xTk5MSHNETHpEUzlvWkhBZ01CQUFHamNqQndNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqQkJnd0ZvQVVOaDNvNHAyQzBnRVl0VEpyRHRkREM1RllRem93RGdZRFZSMFBBUUgvQkFRREFnZUFNQjBHQTFVZERnUVdCQlNwZzRQeUdVakZQaEpYQ0JUTXphTittVjhrOVRBUUJnb3Foa2lHOTJOa0JnVUJCQUlGQURBTkJna3Foa2lHOXcwQkFRVUZBQU9DQVFFQUVhU2JQanRtTjRDL0lCM1FFcEszMlJ4YWNDRFhkVlhBZVZSZVM1RmFaeGMrdDg4cFFQOTNCaUF4dmRXLzNlVFNNR1k1RmJlQVlMM2V0cVA1Z204d3JGb2pYMGlreVZSU3RRKy9BUTBLRWp0cUIwN2tMczlRVWU4Y3pSOFVHZmRNMUV1bVYvVWd2RGQ0TndOWXhMUU1nNFdUUWZna1FRVnk4R1had1ZIZ2JFL1VDNlk3MDUzcEdYQms1MU5QTTN3b3hoZDNnU1JMdlhqK2xvSHNTdGNURXFlOXBCRHBtRzUrc2s0dHcrR0szR01lRU41LytlMVFUOW5wL0tsMW5qK2FCdzdDMHhzeTBiRm5hQWQxY1NTNnhkb3J5L0NVdk02Z3RLc21uT09kcVRlc2JwMGJzOHNuNldxczBDOWRnY3hSSHVPTVoydG04bnBMVW03YXJnT1N6UT09IjsKCSJwdXJjaGFzZS1pbmZvIiA9ICJld29KSW05eWFXZHBibUZzTFhCMWNtTm9ZWE5sTFdSaGRHVXRjSE4wSWlBOUlDSXlNREUwTFRBeExUSTNJREEwT2pVd09qVTJJRUZ0WlhKcFkyRXZURzl6WDBGdVoyVnNaWE1pT3dvSkluQjFjbU5vWVhObExXUmhkR1V0YlhNaUlEMGdJakV6T1RBNE1qY3dOVFl4TnpjaU93b0pJblZ1YVhGMVpTMXBaR1Z1ZEdsbWFXVnlJaUE5SUNKaU1UVXhPVGN6WlRoall6WTNaR1JsTXprd056aGlaREF3TUdVNE4yVTNNak5pWWpFME0yVTFJanNLQ1NKdmNtbG5hVzVoYkMxMGNtRnVjMkZqZEdsdmJpMXBaQ0lnUFNBaU1UQXdNREF3TURBNU9UY3dPREUxTUNJN0Nna2lZblp5Y3lJZ1BTQWlNUzR3TGpjaU93b0pJbUZ3Y0MxcGRHVnRMV2xrSWlBOUlDSTNNVEUwTVRFek1UY2lPd29KSW5SeVlXNXpZV04wYVc5dUxXbGtJaUE5SUNJeE1EQXdNREF3TURrNU56QTRNVFV3SWpzS0NTSnhkV0Z1ZEdsMGVTSWdQU0FpTVNJN0Nna2liM0pwWjJsdVlXd3RjSFZ5WTJoaGMyVXRaR0YwWlMxdGN5SWdQU0FpTVRNNU1EZ3lOekExTmpFM055STdDZ2tpZFc1cGNYVmxMWFpsYm1SdmNpMXBaR1Z1ZEdsbWFXVnlJaUE5SUNKQ05qTkJSVFZGUXkwMk1qQkNMVFF4TWtFdFFqRTVOQzAzTlVJM01EVTNNams0TTBNaU93b0pJbWwwWlcwdGFXUWlJRDBnSWpjM05UZzVNVGc1TWlJN0Nna2lkbVZ5YzJsdmJpMWxlSFJsY201aGJDMXBaR1Z1ZEdsbWFXVnlJaUE5SUNJeE56VTVOVE14TXpnaU93b0pJbkJ5YjJSMVkzUXRhV1FpSUQwZ0ltTnZiUzVwYm5SdmJYbHNhV1psTG1OeVpXUnBkSE15TlNJN0Nna2ljSFZ5WTJoaGMyVXRaR0YwWlNJZ1BTQWlNakF4TkMwd01TMHlOeUF4TWpvMU1EbzFOaUJGZEdNdlIwMVVJanNLQ1NKdmNtbG5hVzVoYkMxd2RYSmphR0Z6WlMxa1lYUmxJaUE5SUNJeU1ERTBMVEF4TFRJM0lERXlPalV3T2pVMklFVjBZeTlIVFZRaU93b0pJbUpwWkNJZ1BTQWlZMjl0TG1sdWRHOXRlV3hwWm1VdWFXOXpJanNLQ1NKd2RYSmphR0Z6WlMxa1lYUmxMWEJ6ZENJZ1BTQWlNakF4TkMwd01TMHlOeUF3TkRvMU1EbzFOaUJCYldWeWFXTmhMMHh2YzE5QmJtZGxiR1Z6SWpzS2ZRPT0iOwoJImVudmlyb25tZW50IiA9ICJTYW5kYm94IjsKCSJwb2QiID0gIjEwMCI7Cgkic2lnbmluZy1zdGF0dXMiID0gIjAiOwp9";

要验证的最简单的数据是 purchase-info 字段。不幸的是,此(base64 编码或不透明)数据的 sha1 总和与签名中的数据不匹配。

看过相当多的 Apple 文件格式后,我猜它可能是像 "{$purchaseData}\x00\x00{$environment}\x00\x00{$pod} 这样的形式的组合“。不过,运气不好,他们添加了一个 secret 字符串,这会使整个练习变得毫无意义(但我不明白他们为什么会……)

有什么见解吗?

更新

将不同的收据发送到/verifyReceipt 端点的更多实验表明 pod/environment 字段无关紧要。更重要的是,收据结构中的字段顺序无关紧要。但是,更改 purchase-info 数据中的单个字节会直接产生无效收据。这一切都将加强这样的假设,即只有 purchase-info 值是散列的一部分——但它可能以 secret 作为前缀/后缀。任何人都可以验证(双关语)吗?

最佳答案

请看https://developer.apple.com/library/ios/releasenotes/StoreKit/IAP_ReceiptValidation/index.html中的代码

签名结构为

#pragma pack(push, 1)
struct signature_blob {
uint8_t version;
uint8_t signature[128];
uint32_t cert_len;
uint8_t certificate[];
} *signature_blob_ptr = (struct signature_blob *)signature_bytes;
#pragma pack(pop)

to_be_hashed= signature_blob_ptr->version . base64_decode(purchase_info)

代码在这里

<?php
$plist = file_get_contents($argv[1]);
if(preg_match('/"signature" = "([^"]+)"/',$plist,$s) && preg_match('/"purchase-info" = "([^"]+)"/',$plist,$p)){
$sig= base64_decode($s[1]);
$purchase=base64_decode($p[1]);

$version=substr($sig,0,1);
$cert = substr($sig,133);
$sig = substr($sig,1,128);
$to_be_sign=$version.$purchase;
//get PEM encode
$cert="-----BEGIN CERTIFICATE-----\n".wordwrap(base64_encode($cert),64,"\n",true)."\n-----END CERTIFICATE-----";
$pubkey = openssl_get_publickey($cert);
if(openssl_verify($to_be_sign,$sig,$pubkey) ==1 )
echo "Success\n";
else
echo "Failed\n";
openssl_free_key($pubkey);
}

关于ios - 没有/verifyReceipt 请求的后端 iOS iap 收据验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21323020/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com