When to use NSSecureCoding

Gabriele Petronella picture Gabriele Petronella · Jun 25, 2013 · Viewed 12.3k times · Source

I'm learning about the NSSecureCoding protocol introduced by Apple in iOS 6.

From my understanding so far, it should be used whenever a class encodes/decodes instances of itself, in order to prevent substitution attacks.

I'm wondering whether it would be appropriate to use it in other cases.

Specifically if a class conforms to NSCoding by encoding/decoding its instance variables, as opposed to the whole instance of itself, would it still be advisable to implement NSSecureCoding?


EDIT

Suppose I have a class that is implementing NSCoding like follows

- (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:self.aString forKey:@"aMeaningfulString"];
}

- (id)initWithCoder:(NSCoder *)decoder {
    if((self = [super init])) {
        self.aString = [decoder decodeObjectForKey:@"aMeaningfulString"];
    }
    return self;
}

and suppose also that no XPC is involved. Instances of this class will be archived in a plist stored on disk.

Security-wise, is there any benefit in using -decodeObjectOfClass:forKey: as opposed to -decodeObjectForKey:?

Answer

CodaFi picture CodaFi · Jun 26, 2013

Specifically if a class conforms to NSCoding by encoding/decoding its instance variables, as opposed to the whole instance of itself, would it still be advisable to implement NSSecureCoding?

It depends on the needs of your application. For any old app, persisting things to disk with plain NSCoding is fine, because the information being written, and the application itself, are (should not) be sensitive in nature. But, say you were a bank releasing an application. You may choose to persist some account information, or an API key to disk so you could communicate with your service, verify the identity of the user, etc. You may not want the whole object, but that shouldn't matter. NSCoder doesn't care what is being read, just that it can read it and do its job correctly. This is a problem.

Security-wise, is there any benefit in using -decodeObjectOfClass:forKey: as opposed to -decodeObjectForKey:?

Yes, very much so. The very fact that you're relying on NSCoder to serialize/deserialize an object (let alone the right object) is a huge attack vector. Once a hacker has modified the information in the format used by NSCoder (a plist-like structure, which is both human-readable and very maleable), then there is no way to guarantee that what you're getting back is what you put in. NSCoder doesn't care that someone decided to switch the classes contained in the archive so you're re-constructing an object of a malicious class, and neither does the runtime. In fact, a smart enough hacker would inject a patch into the application to make sure that the deserialized object would induce some sort of undefined state (a stack overflow), which could be used to potentially exploit the entire application.

decodeObjectOfClass:forKey: allows you to force NSCoder to be a lot smarter about deserialization, and it patches what would be a very large hole. That's not to say that you should never use NSCoder without NSSecureCoding, but rather that you have to be smart about what situations you use it in.