112 / 103 / 12
Регистрация: 01.05.2013
Сообщений: 603
1

Безопасность платного приложения

18.07.2013, 12:44. Показов 1825. Ответов 17
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Хочу поднять вопрос безопасности режимов работы платного приложения.

В данном случае рассматривается приложение, которое осуществляются покупки через StoreKit

Если скажем что сам api storekit как бы дырок не содержит, то вот хранение "статусов" покупки в тех же NSUserDefaults вызывает беспокойство, что их можно подменить и заставить приложение думать что уже все куплено.

Могу предложить лишь шифрование всех ключей покупок через md5 с солью, что может хоть както противостоять подмене NSUserDefaults, если она возможна.

----

Вопрос есть ли еще какие либо методы хранения данной информации кроме NSUserDefaults?
И насколько NSUserDefaults являются надежным хранилищем впринципе?

Добавлено через 33 минуты
Так, тучи уже рассеиваются

инструмент для получения уникальных ключей устройства

Objective-C
1
[[UIDevice currentDevice] uniqueIdentifier];
Однако он уже устарел начиная с ios5 то есть не подходит

в ios6

Objective-C
1
[[[UIDevice currentDevice] identifierForVendor] UUIDString];
Но не работает в ios5, опять не подходит

Еще есть смесь из хеша названия бандла (папки) приложения и MAC адреса

https://github.com/gekitz/UIDe... -for-iOS-5

Objective-C
1
2
[[UIDevice currentDevice] uniqueDeviceIdentifier];
[[UIDevice currentDevice] uniqueGlobalDeviceIdentifier];
совместимо в ios5+ , как раз то что нужно

--
можно проверять содержимое NSUserDefaults на соответствие хешей посоленных с uniqueDeviceIdentifier.
Это существенно поднимает уровень сохранности данных на предмет взлома.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
18.07.2013, 12:44
Ответы с готовыми решениями:

Публичный ключ для платного приложения
Недавно увидел что Янедекс открыл свой googleplay. и что меня порадовало там бесплатная...

Безопасность приложения
Добрый вечер. Хотелось бы узнать как можно максимально обезопасить свое приложение. Допустим, мне...

Безопасность приложения
Добрый день коллеги! Суть проблемы такова: Требуется организовать безопасность приложения на...

Безопасность приложения c#+.net
На сколько безопасно приложение на нет с точки зрения открытости кода. Сложно ли декомпилить...

17
182 / 182 / 3
Регистрация: 10.01.2013
Сообщений: 596
18.07.2013, 12:57 2
KeyСhain подходит
0
686 / 613 / 43
Регистрация: 13.01.2011
Сообщений: 1,722
18.07.2013, 13:15 3
Лучший ответ Сообщение было отмечено как решение

Решение

Ай, скажите НЕТ хранению чего либо важного в NSUserDefaults!
Никогда, даже не думайте об этом. Прислушайтесь к mobidevelop'у. Но это "темная" сторона keyChain.

Хранение чего-то там с appstore в keychain тоже имеет свои минусы. Ибо эта информация для приложения, но никак не для девайса.
"хранение статусов" уже за вас сделано на сервере Apple под учеткой пользователя.
Если вы переустановили приложение - есть функция restore. Если не Интернета - это проблемы пользователя.
По хорошему - эта инфа не должна быть у пользователя. Если у Вас есть такие проблемы c хранением - значит ваше приложение должно иметь связть с Вашим же сервером, на котором вся инфа о покупках и лежит.
3
182 / 182 / 3
Регистрация: 10.01.2013
Сообщений: 596
18.07.2013, 13:21 4
Кстати, да. zulkis прав. Статусы покупок хранятся яблочными серверами. И у них в любой момент можно осведомиться о том или ином айтеме. Или, может быть, мы вопрос неправильно поняли? Поясните задачу.
0
112 / 103 / 12
Регистрация: 01.05.2013
Сообщений: 603
23.07.2013, 21:17  [ТС] 5
извиняюсь за долгое отсутствие,
Статусы покупок хранятся яблочными серверами. И у них в любой момент можно осведомиться о том или ином айтеме.
хранят они, это верно, однако если приложение должно работать еще в "оффлайн" режиме. То где хранить информацию о покупках если в не NSUserDefaults ?

KeyСhain подходит
пока не пробовал, а стоит ли? они же могут хранить просто ключ какой нибудь.
заметь я не спрашиваю о хранении 10000 или 100000 элементов в массиве , а просто ключ из ~50 символов
0
686 / 613 / 43
Регистрация: 13.01.2011
Сообщений: 1,722
24.07.2013, 07:19 6
Прислали 1 раз данные с сервера, программа преобразовала себе это в информацию, записала что-то. И юзер этим пользуется. И без разницы онлайн или оффлайн.
0
112 / 103 / 12
Регистрация: 01.05.2013
Сообщений: 603
24.07.2013, 09:36  [ТС] 7
Прислали 1 раз данные с сервера, программа преобразовала себе это в информацию, записала что-то. И юзер этим пользуется. И без разницы онлайн или оффлайн.
так значит записала, и непременно в NSUserDefaults
0
686 / 613 / 43
Регистрация: 13.01.2011
Сообщений: 1,722
24.07.2013, 12:44 8
Да забудьте вы NSUserDefaults.
Например вы покупаете новые книжки.
Вот купили вы книжку, которой у Вас физически на девайсе нет.
Купили - скачали на сервер, положили ее pathUrl в базу, а саму книжку в cache.
И все, работайте с ней, она у Вас есть. Неважно есть ли интернет.
А если переустановите приложение - все равно нужен будет интернет. Хотя бы для скачивания самого приложения.
0
112 / 103 / 12
Регистрация: 01.05.2013
Сообщений: 603
24.07.2013, 13:02  [ТС] 9
короче будь то книжки или ссылки, сохранение данных имеет место быть так или иначе.
0
Peace 2 all shining faces
674 / 535 / 85
Регистрация: 05.03.2010
Сообщений: 1,282
24.07.2013, 15:14 10
для хранения данных используется база данных
для секьюрности - шифрование, а вообще на сервере все лежит, а вы юзаете какой-то снепшот и временное хранилище в виде бд
0
112 / 103 / 12
Регистрация: 01.05.2013
Сообщений: 603
26.07.2013, 13:29  [ТС] 11
короче, так как записи данных не избежать, то можно применить AES шифрование словаря

файлы
NSData-AES.h

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
//  NSData-AES.h
//  Encryption
//
//  Created by Jeff LaMarche on 2/12/09.
//  Copyright 2009 Jeff LaMarche Consulting. All rights reserved.
//
 
#import <Foundation/Foundation.h>
 
@interface NSData(AES)
- (NSData*)AES256EncryptWithKey:(NSString*)key;
 
- (NSData*)AES256DecryptWithKey:(NSString*)key;
@end
NSData-AES.m
Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//
//  NSData-AES.m
//  Encryption
//
//  Created by Jeff LaMarche on 2/12/09.
//  Copyright 2009 Jeff LaMarche Consulting. All rights reserved.
//
 
#import "NSData-AES.h"
#import <CommonCrypto/CommonCryptor.h>
 
@implementation NSData(AES)
 
 
- (NSData*)AES256EncryptWithKey:(NSString*)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
    
    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    NSUInteger dataLength = [self length];
    
    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize           = dataLength + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);
    
    size_t numBytesEncrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);
    
    if (cryptStatus == kCCSuccess)
    {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    
    free(buffer); //free the buffer;
    return nil;
}
 
- (NSData*)AES256DecryptWithKey:(NSString*)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
    
    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    NSUInteger dataLength = [self length];
    
    //See the doc: For block ciphers, the output size will always be less than or
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize           = dataLength + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);
    
    size_t numBytesDecrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          [self bytes], dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesDecrypted);
    
    if (cryptStatus == kCCSuccess)
    {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }
    
    free(buffer); //free the buffer;
    return nil;
}
 
@end
использование через впомогательные функции распаковки

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#pragma mark WriteRead Dict Secur
 
-(NSMutableDictionary *)readDictionaryFromFile:(NSString *)path withSecurKey:(NSString *)key {
    NSData*d = [NSData dataWithContentsOfFile:path];
    if (d) {
        d = [d AES256DecryptWithKey:key];
        if (d) {
            NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:d];
            if (dict) {
                 // полное мутирование словаря
                 NSMutableDictionary* mudict = CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (__bridge CFPropertyListRef)(dict), kCFPropertyListMutableContainers));
                return mudict;
            }
        }
    }
    return [NSMutableDictionary new];
}
 
-(bool)writeDictionary:(NSDictionary *)dict toFile:(NSString *)path withSecurKey:(NSString *)key {
    NSData*dt = [NSKeyedArchiver archivedDataWithRootObject:dict];
    dt = [dt AES256EncryptWithKey:key];
    return [dt writeToFile:path atomically:YES];
}
пример кода

Objective-C
1
2
3
4
// << чтение
NSMutableDictionary *dict = [self readDictionaryFromFile:@"Путь к файлу" withSecurKey:@"ключ шифрования"];
// << запись
[self writeDictionary:dict toFile:@"Путь к файлу" withSecurKey:@"ключ шифрования"];
0
Peace 2 all shining faces
674 / 535 / 85
Регистрация: 05.03.2010
Сообщений: 1,282
26.07.2013, 15:26 12
а можете объяснить, что вами движет, когда вы вместо простого статического метода, который принимал бы на вход NSData и ключ, создаете категорию?

насколько мне известно, категории лучше создавать в крайних случаях, когда это действительно необходимо, а за вами наблюдаю то, что вы всегда создаете категории для любой вспомогательной функциональности

оно конечно красиво выглядит, но не всегда интуитивно понятно, что за какими-то утилитками можно лезть в сам объект, так как изначально там такой функциональности нету

просто интересно
0
112 / 103 / 12
Регистрация: 01.05.2013
Сообщений: 603
26.07.2013, 16:49  [ТС] 13
который принимал бы на вход NSData и ключ, создаете категорию
это всего лишь копия NSData+AES с просторов инета

насколько мне известно, категории лучше создавать в крайних случаях, когда это действительно необходимо, а за вами наблюдаю то, что вы всегда создаете категории для любой вспомогательной функциональности
нет, я больше склонен создавать 1 класс, включающий все категории для всех классов, которые этого требуют

Все что выше это просто исходник, никто не мешает его переделать в более удобный вид.
0
182 / 182 / 3
Регистрация: 10.01.2013
Сообщений: 596
26.07.2013, 16:51 14
Цитата Сообщение от noname_club Посмотреть сообщение
я больше склонен создавать 1 класс, включающий все категории для всех классов, которые этого требуют
Это как?
0
112 / 103 / 12
Регистрация: 01.05.2013
Сообщений: 603
26.07.2013, 16:56  [ТС] 15
Это как?
типа такого

Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@interface NSArray (ArrayExt)
 
-(id) index: (int) ind;
-(void) cu_log;
-(NSString*) cu_implode: (NSString*) delemitter;
 
-(NSArray*) cu_preg_filter: (NSString*) filter
                     value: (id) value;
 
-(NSMutableArray*) cu_SortByDictionaryField: (NSString*) fieldname;
 
 
@end
 
 
@interface NSMutableArray (ArrayMuExt)
 
-(void) add: (id) object;
-(void) cu_SortAsStringArray;
-(void) cu_SortAsNumberArray;
-(void) cu_SortAsIntegerArray;
-(void) cu_Reverse;
 
@end
 
// расширенная строка
 
@interface NSString (StringExt)
 
-(NSMutableArray*) cu_explode: (NSString*) delemitter
                        empty: (bool) empty;
 
-(bool) cu_preg_match:(NSString*) filter
                value: (id) value;
 
-(NSString*) cu_trim;
 
-(NSString*) cu_translit;
 
-(NSString*) cu_htmlstriptags;
 
-(NSString*) cu_replace: (id) findstring
                   with: (id) replacer;
 
-(NSString*) cu_charAtIndex: (int) index;
 
-(NSString*) cu_substringFrom: (int) from
                       length: (int) length;
 
-(NSString*) cu_extractFileName;
 
-(void) cu_log;
 
-(NSString*) cu_ReverseString;
 
-(NSString*) cu_str_pad_left:(NSString*) str
                    length: (int) length;
 
@end
ну и соответвенно в m файле структура идентичная, перечисление описания работы категорий
0
182 / 182 / 3
Регистрация: 10.01.2013
Сообщений: 596
26.07.2013, 16:59 16
Ой, ну зачем я спросил?
0
112 / 103 / 12
Регистрация: 01.05.2013
Сообщений: 603
26.07.2013, 17:04  [ТС] 17
Ой, ну зачем я спросил?
если на то пошло, в h файлах Foundation применяется похожий метод. Категории, особенно для словарей и массивов тупо свалены друг за другом в 1 заголовочном файле. Так что ничего необычного.
0
686 / 613 / 43
Регистрация: 13.01.2011
Сообщений: 1,722
26.07.2013, 19:03 18
noname_club, ой, а чтож в коде все так... Красиво

cu_translit - Это не ку, это кю. (c)

Добавлено через 2 минуты
Vorona, А я вот люблю категории. И если категории хорошо именовать, например NSData+Crypto, то сразу понятно что и как. А потом можно NSString+Crypto сделать, а внутри использовать NSData+Crypto. Вообще класс, имхо.
1
26.07.2013, 19:03
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.07.2013, 19:03
Помогаю со студенческими работами здесь

Безопасность PHP приложения.
Добрый вечер. Настал тот день и тот час, когда мою систему на PHP нужно выложить в сеть. Система...

Безопасность приложения: хранение в коде паролей к бд сервера
Хочу из клиента на прямую подключаться к базе. Данные для подключения придется хранить где то в...

Почта платного хостинга
Всем привет. Дико заранее извиняюсь, если не туда написал, но просто не знал в какой раз дел...

Использование платного шаблона
Всем доброго времени суток! Уважаемые, подскажите, пожалуйста, чем грозит использование платной...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru