【问题标题】:In-App Purchase Receipt Validation Contradiction应用内购买收据验证矛盾
【发布时间】:2013-07-31 21:10:18
【问题描述】:

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

在“Verifying Store Receipts”中:

注意:在 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 的“缓解策略”,我的应用很容易受到攻击。

如果我这样做该死,如果我不这样做该死。我有什么遗漏吗?

【问题讨论】:

    标签: ios in-app-purchase storekit receipt


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 感谢 WDUK。在提出问题之前,我已经向他们发送了反馈。 ;) 对于服务器不可用的情况,我认为最好的方法是执行它们仅为运行 iOS 5.1 或更低版本的设备提供的代码。这样,如果他们更改收据,损失是有限的。
    • 是的,这基本上就是我的回答。 Apple 允许这种以前不推荐的做法,如果您没有自己的服务器(Apple 似乎理解这种情况),这确实是您唯一可以做的事情。由于使用了缓解方法,Apple(而不是开发人员)不会破坏 iOS 5.1.x 及更低版本的兼容性,这取决于 Apple。他们会怎么做我不知道,也许他们只会在 iOS 5 过时的时候改变收据的格式......
    【解决方案2】:

    Apple 目前还建议在设备上进行收据验证。请参阅Validating receipts locally 和 WWDC 2013 谈话Using receipts to protect your digital sales

    【讨论】:

    • 抱歉,但了解如何使用您提供的这些链接验证收据,这些链接由模糊之王 Apple 创建,就像通过观看两只猴子打板球来了解脑部手术一样。
    • 是的,应用内购买有点痛苦。我已经为此工作了一个月左右,但仍在工作。哪些信息会有所帮助?
    • 全部。我对 SSL、证书等的了解为零。我需要看一个例子,从上到下如何做到这一点。显然我知道我必须改变一些方法来防止自动破解,但如果我能看到整个事情正常工作,我会很高兴。
    • 在过去的几天里,我的 iOS7 设备本地收据验证似乎工作了。只是在初始测试阶段。大约 500 行代码。一般来说,我愿意分享它,但我确实担心我的应用程序中的这些与安全相关的详细信息会进入其他人的应用程序,并使人们更容易破坏我的应用程序的安全性。想法?
    猜你喜欢
    • 2011-10-12
    • 2010-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多