13 May 2012

Как защитить in-App Purchase от ломалок

Development for iOS
До недавнего времени 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. Метод не претендует на звание «самого лучшего». Если у вас, коллеги есть замечания и еще идеи по этому поводу — пишите.
Tags:in-App Purchasexcodeiosантивзлом
Hubs: Development for iOS
+28
7.1k 146
Comments 30