2014-03-13 51 views
1

我有一個SGBContainer類的對象,它有一個名爲objects的數組,其中包含類SGBObject的對象。目前,它們各自實施NSCoding而不是NSSecureCoding。該-initWithCoder:SGBContainer看起來是這樣的:如何使用NSSecureCoding來保證集合類的內容?

- (id)initWithCoder:(NSCoder *)aCoder 
{ 
    self = [self init]; 
    if (self) 
    { 
     _objects = [aCoder decodeObjectForKey:@"objects"]; 
    } 
} 

我想切換到使用NSSecureCoding,從我所知道的,這將意味着改變上述這樣:

- (id)initWithCoder:(NSCoder *)aCoder 
{ 
    self = [self init]; 
    if (self) 
    { 
     _objects = [aCoder decodeObjectOfClass:[NSArray class] forKey:@"objects"]; 
    } 
} 

...這沒有太大的改進,因爲數組的內容將被實例化,無論他們的類是什麼。如何確保數組僅包含類SGBObject的對象而不實例化它們?

回答

3

雖然從文檔中不完全清楚(而且聽起來像一個奇怪的非語法方法名稱),但這是-decodeObjectOfClasses:forKey:所做的。你會做類似如下:

NSSet *classes = [NSSet setWithObjects:[NSArray class], [SGBObject class], nil]; 
_objects = [aCoder decodeObjectOfClasses:classes forKey:@"objects"]; 

(信貸,這是由於:見NSSecureCoding trouble with collections of custom class

1

由於NSCoder不是收集意識,所以沒有直接的方法與NSSecureCoding做到這一點。您必須手動清理陣列,以確保它僅包含SGBObject類型的對象(公平地說,這種對象可以擊敗NSSecureCoding的目的)。

另一種方法是自己編碼和解碼數組,而不是依靠NSCoder這樣做。

+1

好的,謝謝。雷達,然後... http://openradar.appspot.com/16314084 – Simon

0

嘗試 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:archivedData]; unarchiver.requiresSecureCoding = YES; MyClass *myClass = [unarchiver decodeObjectOfClass:[MyClass class] forKey:@"root"]; 如果不設置unarchiver.requiresSecureCoding = YES,那麼沒有檢查會應用。

1

Sean D.的回答是正確的,以解除阻塞的代碼,但有一個警告:基礎不保證數組內的類類型,如果他們是基礎類。例如。下面的代碼演示了此問題:

@implementation Serializable 
- (id)initWithCoder:(NSCoder *)aDecoder { 
    return [super init]; 
} 
- (void)encodeWithCoder:(NSCoder *)aCoder { 
} 
+ (BOOL)supportsSecureCoding { 
    return YES; 
} 
@end 

int main(int argc, const char * argv[]) { 

    NSArray *foo = @[ @1, @"Gotcha", [Serializable new] ]; 
    NSMutableData *archive = [NSMutableData data]; 
    NSKeyedArchiver *archiver = 
     [[NSKeyedArchiver alloc] initForWritingWithMutableData:archive]; 
    archiver.requiresSecureCoding = YES; 
    [archiver encodeObject:foo forKey:@"root"]; 
    [archiver finishEncoding]; 

    NSKeyedUnarchiver *unarchiver = 
    [[NSKeyedUnarchiver alloc] initForReadingWithData:archive]; 
    unarchiver.requiresSecureCoding = YES; 
    NSSet *classes = [NSSet setWithArray:@[ [NSArray class], [Serializable class] ]]; 
    // Should throw, but it does not. 
    NSArray *loaded = [unarchiver decodeObjectOfClasses:classes forKey:NSKeyedArchiveRootObjectKey]; 
    if (loaded.count > 2 && ![loaded[0] isKindOfClass:[Serializable class]]) { 
    NSLog(@"Successfully performed object substitution attack."); 
    NSLog(@"Class: %@", [loaded[0] class]); // All 3 objects are 
    return 1; 
    } 
    return 0; 
} 
相關問題