Apple提供了两份关于收据验证的文件,显然是相互矛盾的陈述。
注意:在iOS上,商店收据的内容和格式是私有的 并且可能会有变化。 您的应用程序不应尝试解析 收据数据直接。
然而,在“In-App Purchase Receipt Validation on iOS”中提供了示例代码,其中解析并验证了商店收据,作为安全漏洞的“缓解策略”的一部分:
// Check the validity of the receipt. If it checks out then also ensure the transaction is something
// we haven't seen before and then decode and save the purchaseInfo from the receipt for later receipt validation.
- (BOOL)isTransactionAndItsReceiptValid:(SKPaymentTransaction *)transaction
{
if (!(transaction && transaction.transactionReceipt && [transaction.transactionReceipt length] > 0))
{
// Transaction is not valid.
return NO;
}
// Pull the purchase-info out of the transaction receipt, decode it, and save it for later so
// it can be cross checked with the verifyReceipt.
NSDictionary *receiptDict = [self dictionaryFromPlistData:transaction.transactionReceipt];
NSString *transactionPurchaseInfo = [receiptDict objectForKey:@"purchase-info"];
NSString *decodedPurchaseInfo = [self decodeBase64:transactionPurchaseInfo length:nil];
NSDictionary *purchaseInfoDict = [self dictionaryFromPlistData:[decodedPurchaseInfo dataUsingEncoding:NSUTF8StringEncoding]];
NSString *transactionId = [purchaseInfoDict objectForKey:@"transaction-id"];
NSString *purchaseDateString = [purchaseInfoDict objectForKey:@"purchase-date"];
NSString *signature = [receiptDict objectForKey:@"signature"];
// Convert the string into a date
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];
NSDate *purchaseDate = [dateFormat dateFromString:[purchaseDateString stringByReplacingOccurrencesOfString:@"Etc/" withString:@""]];
if (![self isTransactionIdUnique:transactionId])
{
// We've seen this transaction before.
// Had [transactionsReceiptStorageDictionary objectForKey:transactionId]
// Got purchaseInfoDict
return NO;
}
// Check the authenticity of the receipt response/signature etc.
BOOL result = checkReceiptSecurity(transactionPurchaseInfo, signature,
(__bridge CFDateRef)(purchaseDate));
if (!result)
{
return NO;
}
// Ensure the transaction itself is legit
if (![self doTransactionDetailsMatchPurchaseInfo:transaction withPurchaseInfo:purchaseInfoDict])
{
return NO;
}
// Make a note of the fact that we've seen the transaction id already
[self saveTransactionId:transactionId];
// Save the transaction receipt's purchaseInfo in the transactionsReceiptStorageDictionary.
[transactionsReceiptStorageDictionary setObject:purchaseInfoDict forKey:transactionId];
return YES;
}
如果我理解正确,如果我验证收据,当Apple决定更改收据格式时,我的应用可能会停止工作。
如果我不验证收据,我不会遵循Apple的“缓解策略”,我的应用程序很容易受到攻击。
如果我这样做,该死的,如果我不这样做,该死的。有什么我想念的吗?答案 0 :(得分:3)
他们强烈建议您使用自己的服务器作为验证中介,因为这样可以清晰安全地通过App Store获取所有iOS版本。这无论如何都是不被诅咒的最佳途径。
如果您必须直接从设备执行验证到App Store,那么只有当应用程序在5.1.x及更低版本上运行时,才会使用其缓解策略。对于iOS6及更高版本,请使用提供的推荐方法。
虽然您不应该直接解析收据,但发现的漏洞使Apple在如何解决这个问题的过程中陷入困境,并决定应用程序开发人员实施检查。这意味着当用户更新应用程序时,收据现在再次受到保护(无论iOS版本如何),从而提供更好的修复范围。作为一个副作用,这意味着你必须打破通常的做法(但Apple允许你这样做)。
我同意文档在这方面并不完全清楚,并且可以进一步澄清(您应该从底部的文档页面给出反馈)。 Apple发布了缓解策略,他们确实表示应该在iOS 5.1.x及更低版本上使用它来解决漏洞。如果他们改变IAP收据的格式/内容,他们就有责任。
答案 1 :(得分:0)
Apple目前还在推荐设备收据验证。请参阅Validating receipts locally和WWDC 2013 talk Using receipts to protect your digital sales。