До недавнего времени inApp Purchase был достаточно надежным механизмом защиты от взлома приложений. Если разработчик хотел, чтобы его приложение не попадало в список ломаных — он просто выпускал его бесплатным с продажами внутри. Схема работала. Но после появления в Cydia 'iAP Cracker' — ситуация изменилась.
Под катом описан метод, как можно вполне легально обойти эти ломалки.
Я задумался о защите от взлома inApp Purchase после того, как увидел статистику моего приложения IQ pro. Оно построено на модели freemium. В свой статистике я видел огромное количество продаж — а в статистике от Apple цифры были совершенно другие (намного меньше). Тогда я не следил за тем, какие ломалки бывают. Но когда в отзывах люди начали писать, что «пользуйтесь 'iAP Cracker'» — все стало ясно.
Метод защиты описанный ниже использует механизм, который Apple рекомендует при продаже с последующей проверкой и загрузкой данных с вашего сервера. По сути, я перенес проверку тикета с удаленного сервера на само приложение.
В качестве библиотеки для inApp Purchase используется MKStoreKit.
Шаги:
1. В MKStoreManager.h — включаем #define SERVER_PRODUCT_MODEL 1
2. Оригинальный — (BOOL)verifyReceipt — заменяем на:
- (BOOL)verifyReceipt:(NSData*)receiptData {
//NSString *urlsting = @"https://sandbox.itunes.apple.com/verifyReceipt";
NSString *urlsting = @"https://buy.itunes.apple.com/verifyReceipt";
NSURL *url = [NSURL URLWithString:urlsting];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
NSString *st = [receiptData base64EncodingWithLineLength:[receiptData length]];
NSString *json = [NSString stringWithFormat:@"{"receipt-data":"%@"}", st];
[theRequest setHTTPBody:[json dataUsingEncoding:NSUTF8StringEncoding]];
[theRequest setHTTPMethod:@"POST"];
[theRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
NSString *length = [NSString stringWithFormat:@"%d", [json length]];
[theRequest setValue:length forHTTPHeaderField:@"Content-Length"];
NSHTTPURLResponse* urlResponse = nil;
NSError *error = [[NSError alloc] init];
NSData *responseData = [NSURLConnection sendSynchronousRequest:theRequest
returningResponse:&urlResponse
error:&error];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *dic = [responseString JSONValue];
NSInteger status = [[dic objectForKey:@"status"] intValue];
BOOL retVal = NO;
if (status == 0) {
retVal = YES;
}
return retVal;
}
3. Добавить в проект библиотеку для работы с JSON (http://code.google.com/p/json-framework )
4. Все :-)
Что происходит:
После получения receipt — он отправляется еще раз на сервера Apple для проверки, а по ответу можно уже опредилить все, что надо.
P.S. Метод не претендует на звание «самого лучшего». Если у вас, коллеги есть замечания и еще идеи по этому поводу — пишите.
Автор: cohe4ko