【发布时间】:2013-07-31 21:10:18
【问题描述】:
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 的“缓解策略”,我的应用很容易受到攻击。
如果我这样做该死,如果我不这样做该死。我有什么遗漏吗?
【问题讨论】:
标签: ios in-app-purchase storekit receipt