Actualmente estoy usando NSUserDefaults, pero he escuchado que Jailbreakers puede cambiar fácilmente estos valores y hacer trampa en Game Center. ¿Debería encriptar el valor que almaceno? ¿Debo usar llavero? ¿Debo almacenar el valor en binario en NSUserDefualts usando BOOL (probablemente no)? ¿Cuál es la mejor manera de almacenar un puntaje alto para evitar el pirateo y cómo se hace?¿Cuál es la mejor manera de guardar los mejores puntajes en el iPhone para evitar piratear?
Respuesta
Cualquier dato que necesite ser accesible solo a través de un código y debería ser seguro cabría perfectamente en KeyChain.
Si se convierte en algo más que solo un poco de datos, cifrarlo y almacenarlo en el directorio de documentos también podría hacer el trabajo. Pero si alguien realmente lo desea, desmontan su aplicación y tratan de localizar la clave de cifrado. No es fácil, pero se puede hacer.
Puede encriptar los valores usando un par de claves codificadas. Tendrá que guardar los datos como un objeto NSData
y puede continuar usando NSUserDefaults
.
Esto question te puede interesar.
Este es el código que estoy usando, algunos de ellos se han tomado de Internet
Tomé la idea de éste: https://github.com/matthiasplappert/Secure-NSUserDefaults
cómo utilizar
en su AppDelegate .m
#import "NSUserDefaults+SecureUserDefaults.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[NSUserDefaults setSecret:@"soem secret string"]; //Cracker can still read the secret string from the binary through
// other initialize step
}
cuando desea utilizar
[[NSUserDefaults standardUserDefaults] arrayForKey:@"key" defaultValue:nil]; // if the content is modified or not exist will return default value that passed in
[[NSUserDefaults standardUserDefaults] setSecureObject:object forKey:@"key"];
// check more method in NSUserDefaults+SecureUserDefaults.h
código aquí
NSData + Encryption_AES256.h
#import <Foundation/Foundation.h>
@interface NSData (Encryption_AES256)
- (NSData *)encryptedDataWithKey:(NSData *)key;
- (NSData *)decryptedDataWithKey:(NSData *)key;
@end
NSData + Encryption_AES256.m
#import "NSData+Encryption_AES256.h"
#import <CommonCrypto/CommonCryptor.h>
// Key size is 32 bytes for AES256
#define kKeySize kCCKeySizeAES256
@implementation NSData (Encryption_AES256)
- (NSData*) makeCryptedVersionWithKeyData:(const void*) keyData ofLength:(int) keyLength decrypt:(bool) decrypt
{
// Copy the key data, padding with zeroes if needed
char key[kKeySize];
bzero(key, sizeof(key));
memcpy(key, keyData, keyLength > kKeySize ? kKeySize : keyLength);
size_t bufferSize = [self length] + kCCBlockSizeAES128;
void* buffer = malloc(bufferSize);
size_t dataUsed;
CCCryptorStatus status = CCCrypt(decrypt ? kCCDecrypt : kCCEncrypt,
kCCAlgorithmAES128,
kCCOptionPKCS7Padding | kCCOptionECBMode,
key, kKeySize,
NULL,
[self bytes], [self length],
buffer, bufferSize,
&dataUsed);
switch(status)
{
case kCCSuccess:
return [NSData dataWithBytesNoCopy:buffer length:dataUsed];
case kCCParamError:
NSLog(@"Error: NSDataAES256: Could not %s data: Param error", decrypt ? "decrypt" : "encrypt");
break;
case kCCBufferTooSmall:
NSLog(@"Error: NSDataAES256: Could not %s data: Buffer too small", decrypt ? "decrypt" : "encrypt");
break;
case kCCMemoryFailure:
NSLog(@"Error: NSDataAES256: Could not %s data: Memory failure", decrypt ? "decrypt" : "encrypt");
break;
case kCCAlignmentError:
NSLog(@"Error: NSDataAES256: Could not %s data: Alignment error", decrypt ? "decrypt" : "encrypt");
break;
case kCCDecodeError:
NSLog(@"Error: NSDataAES256: Could not %s data: Decode error", decrypt ? "decrypt" : "encrypt");
break;
case kCCUnimplemented:
NSLog(@"Error: NSDataAES256: Could not %s data: Unimplemented", decrypt ? "decrypt" : "encrypt");
break;
default:
NSLog(@"Error: NSDataAES256: Could not %s data: Unknown error", decrypt ? "decrypt" : "encrypt");
}
free(buffer);
return nil;
}
- (NSData*)encryptedDataWithKey:(NSData *)key
{
return [self makeCryptedVersionWithKeyData:[key bytes] ofLength:[key length] decrypt:NO];
}
- (NSData*)decryptedDataWithKey:(NSData *)key
{
return [self makeCryptedVersionWithKeyData:[key bytes] ofLength:[key length] decrypt:YES];
}
@end
NSUserDefaults + SecureUserDefaults.h
//
// NSUserDefaults+SecureUserDefaults.h
// PocketMoneyExchanger
//
// Created by Xiliang Chen on 12-1-17.
// Copyright (c) 2012年 Xiliang Chen. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSUserDefaults (SecureUserDefaults)
+ (void)setSecret:(NSString *)secret;
- (id)objectForKey:(NSString *)defaultName defaultValue:(id)value;
- (void)setSecureObject:(id)value forKey:(NSString *)defaultName;
- (NSString *)stringForKey:(NSString *)defaultName defaultValue:(NSString *)value;
- (NSArray *)arrayForKey:(NSString *)defaultName defaultValue:(NSArray *)value;
- (NSDictionary *)dictionaryForKey:(NSString *)defaultName defaultValue:(NSDictionary *)value;
- (NSData *)dataForKey:(NSString *)defaultName defaultValue:(NSData *)value;
- (NSArray *)stringArrayForKey:(NSString *)defaultName defaultValue:(NSArray *)value;
- (NSInteger)integerForKey:(NSString *)defaultName defaultValue:(NSInteger)value;
- (float)floatForKey:(NSString *)defaultName defaultValue:(float)value;
- (double)doubleForKey:(NSString *)defaultName defaultValue:(double)value;
- (BOOL)boolForKey:(NSString *)defaultName defaultValue:(BOOL)value;
- (void)setSecureInteger:(NSInteger)value forKey:(NSString *)defaultName;
- (void)setSecureFloat:(float)value forKey:(NSString *)defaultName;
- (void)setSecureDouble:(double)value forKey:(NSString *)defaultName;
- (void)setSecureBool:(BOOL)value forKey:(NSString *)defaultName;
@end
NSUserDefaults + SecureUserDefaults.m
//
// NSUserDefaults+SecureUserDefaults.m
// PocketMoneyExchanger
//
// Created by Xiliang Chen on 12-1-17.
// Copyright (c) 2012年 Xiliang Chen. All rights reserved.
//
#import "NSUserDefaults+SecureUserDefaults.h"
#import "NSData+Encryption_AES256.h"
static NSData *secretData;
@implementation NSUserDefaults (SecureUserDefaults)
+ (void)setSecret:(NSString *)secret {
secretData = [secret dataUsingEncoding:NSUnicodeStringEncoding];
}
- (id)objectForKey:(NSString *)defaultName defaultValue:(id)value {
id obj = [self objectForKey:defaultName];
if ([obj isKindOfClass:[NSData class]]) {
NSData *secureData = obj;
NSData *data = [secureData decryptedDataWithKey:secretData];
if (data) {
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
}
return value;
}
- (void)setSecureObject:(id)value forKey:(NSString *)defaultName {
if (value == nil || defaultName == nil) {
return [self setObject:value forKey:defaultName];
}
NSData *tobesaved = [NSKeyedArchiver archivedDataWithRootObject:value];
NSData *secureData = [tobesaved encryptedDataWithKey:secretData];
//NSAssert(secureData != nil, @"fail to encrpty data");
[self setObject:secureData forKey:defaultName];
}
- (NSString *)stringForKey:(NSString *)defaultName defaultValue:(NSString *)value {
id obj = [self objectForKey:defaultName defaultValue:value];
if ([obj isKindOfClass:[NSString class]]) {
return obj;
}
return value;
}
- (NSArray *)arrayForKey:(NSString *)defaultName defaultValue:(NSArray *)value {
id obj = [self objectForKey:defaultName defaultValue:value];
if ([obj isKindOfClass:[NSArray class]]) {
return obj;
}
return value;
}
- (NSDictionary *)dictionaryForKey:(NSString *)defaultName defaultValue:(NSDictionary *)value {
id obj = [self objectForKey:defaultName defaultValue:value];
if ([obj isKindOfClass:[NSDictionary class]]) {
return obj;
}
return value;
}
- (NSData *)dataForKey:(NSString *)defaultName defaultValue:(NSData *)value {
id obj = [self objectForKey:defaultName defaultValue:value];
if ([obj isKindOfClass:[NSData class]]) {
return obj;
}
return value;
}
- (NSArray *)stringArrayForKey:(NSString *)defaultName defaultValue:(NSArray *)value {
id obj = [self objectForKey:defaultName defaultValue:value];
if ([obj isKindOfClass:[NSArray class]]) {
for (id item in obj) {
if (![item isKindOfClass:[NSString class]]) {
return value;
}
}
return obj;
}
return value;
}
- (NSInteger)integerForKey:(NSString *)defaultName defaultValue:(NSInteger)value {
id obj = [self objectForKey:defaultName defaultValue:[NSNumber numberWithInteger:value]];
if ([obj isKindOfClass:[NSNumber class]]) {
return [obj integerValue];
}
return value;
}
- (float)floatForKey:(NSString *)defaultName defaultValue:(float)value {
id obj = [self objectForKey:defaultName defaultValue:[NSNumber numberWithFloat:value]];
if ([obj isKindOfClass:[NSNumber class]]) {
return [obj floatValue];
}
return value;
}
- (double)doubleForKey:(NSString *)defaultName defaultValue:(double)value {
id obj = [self objectForKey:defaultName defaultValue:[NSNumber numberWithDouble:value]];
if ([obj isKindOfClass:[NSNumber class]]) {
return [obj doubleValue];
}
return value;
}
- (BOOL)boolForKey:(NSString *)defaultName defaultValue:(BOOL)value {
id obj = [self objectForKey:defaultName defaultValue:[NSNumber numberWithBool:value]];
if ([obj isKindOfClass:[NSNumber class]]) {
return [obj boolValue];
}
return value;
}
- (void)setSecureInteger:(NSInteger)value forKey:(NSString *)defaultName {
[self setSecureObject:[NSNumber numberWithInteger:value] forKey:defaultName];
}
- (void)setSecureFloat:(float)value forKey:(NSString *)defaultName {
[self setSecureObject:[NSNumber numberWithFloat:value] forKey:defaultName];
}
- (void)setSecureDouble:(double)value forKey:(NSString *)defaultName {
[self setSecureObject:[NSNumber numberWithDouble:value] forKey:defaultName];
}
- (void)setSecureBool:(BOOL)value forKey:(NSString *)defaultName {
[self setSecureObject:[NSNumber numberWithBool:value] forKey:defaultName];
}
@end
- 1. ¿Cuál es la mejor manera de almacenar/calcular los puntajes de los usuarios?
- 2. La mejor manera de guardar datos en el iPhone
- 3. ¿Cuál es la mejor manera de evitar maven-jar?
- 4. ¿Cuál es la mejor manera de organizar múltiples subvistas?
- 5. ¿Cuál es el mejor campo para guardar el cumpleaños?
- 6. ¿Cuál es la mejor manera de guardar los contenidos de una ArrayList?
- 7. ¿Cuál es la mejor manera de guardar mis POJOs en Jackrabbit JCR?
- 8. ¿Cuál es la mejor manera de hacer una aplicación de mapas para el iPhone
- 9. Cuál es la mejor manera de evitar pérdidas de memoria en la aplicación WPF PRISM/MVVM
- 10. ¿Cuál es la manera de implementar la funcionalidad Guardar/Cargar?
- 11. ¿Cuál es la mejor manera, utilizando el patrón de diseño "estatal", para cambiar los estados?
- 12. ¿Cuál es la mejor manera de guardar la configuración del usuario en la aplicación Java?
- 13. ¿Cuál es la mejor manera de empaquetar el código JavaScript sin tener fallas en el rendimiento?
- 14. ¿Cuál es la mejor manera de guardar datos localmente en una aplicación WPF?
- 15. ¿Cuál es la mejor manera para que Lazy cargue imágenes en iPhone?
- 16. ¿Cuál es la mejor manera de comunicarse entre los AppDomains?
- 17. ¿Cuál es la mejor manera de guardar una página web completa en un servidor Linux?
- 18. ¿Cuál es la mejor manera de implementar una API REST de registro para iPhone/Android?
- 19. ¿Cuál es la mejor manera de proporcionar localización para Enumeraciones?
- 20. Mejores prácticas: ¿Cuál es la mejor manera de construir encabezados y pies de página?
- 21. ¿Cuál es la mejor manera de documentar el código f #?
- 22. ¿Cuál es la mejor manera de comenzar a utilizar MAPI?
- 23. ¿Cuál es la mejor manera de guardar datos XML en SQL Server?
- 24. ¿Cómo puede evitar que puntajes altos falsos aparezcan en una lista global de puntajes altos?
- 25. ¿Cuál es la mejor manera de dibujar en la consola?
- 26. ¿Cuál es la mejor manera de probar el código GWT
- 27. ¿Cómo calcular los puntajes?
- 28. Cuál es la mejor manera de realizar jQuery .change()
- 29. ¿Cuál es la mejor manera de registrar información de depuración en una aplicación de iPhone?
- 30. ¿Cuál es la mejor manera de evitar el hecho de que TODOS los bytes de Java están firmados?
¿No hay manera para un dispositivo con jailbreak para acceder al llavero? ¿Debo todavía encriptar los datos que almaceno en el llavero usando el cifrado NSData, o está siendo almacenado en el llavero lo suficiente? – jadengeller
Bueno, es posible, pero el llavero es un elemento al que solo pueden acceder las aplicaciones que comparten el mismo identificador de paquete. – rckoenes