4

Apple 提供了两份关于收据验证的文件,其中的陈述显然相互矛盾。

在“验证商店收据”中:

注意:在 iOS 上,商店收据的内容和格式是私密的,可能会发生变化。您的应用程序不应尝试直接解析收据数据

然而,在“ iOS 上的 In-App Purchase Receipt Validation ”示例代码中,作为安全漏洞“缓解策略”的一部分,提供了对商店收据进行解析和验证的示例代码:

// 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 的“缓解策略”,我的应用程序很容易受到攻击。

如果我这样做该死,如果我不这样做该死。有什么我想念的吗?

4

2 回答 2

3

他们强烈建议使用您自己的服务器作为验证的中介,因为这将为所有版本的 iOS 提供通往 App Store 的清晰安全通道。这真的是最好的方法,不要被诅咒。

如果您必须直接从设备到 App Store 执行验证,那么您仅在应用程序在 5.1.x 及以下版本上运行时才使用他们的缓解策略。对于 iOS6 及更高版本,请使用提供的推荐方式。

虽然您总是不应该直接解析收据,但发现的漏洞让 Apple 在如何解决这个问题上陷入困境,并决定应用程序开发人员实施检查。这意味着当用户更新应用程序时,收据现在再次受到保护(无论 iOS 版本如何),从而提供更好的修复覆盖率。作为一个副作用,这意味着你必须打破你通常应该做的事情(但苹果已经允许你这样做)。

我同意文档对此并不完全清楚,并且可以进一步澄清(您应该从底部的文档页面向他们提供反馈)。Apple 已经发布了缓解策略,他们确实声明应该在 iOS 5.1.x 及更低版本上使用它来解决漏洞。如果他们更改 IAP 收据的格式/内容,他们有责任。

于 2013-07-31T14:18:10.633 回答
0

Apple 目前还建议在设备上进行收据验证。请参阅在本地验证收据和 WWDC 2013 演讲使用收据保护您的数字销售

于 2013-10-05T22:05:05.570 回答