NSSecureCoding
A short post for this week: everything you need to know about NSSecure
.
NSSecure
is a protocol introduced in the iOS 6 / OS X Mountain Lion SDKs. Aside from a few mentions at WWDC, NSSecure
remains relatively obscure—most developers have perhaps heard of it, but perhaps never went so far as to look up what it does.
NSSecure
extends the NSCoding
protocol by adding the class method supports
:
By conforming to NSSecure
and returning YES
for +supports
, a class declares that it handles encoding and decoding of instances of itself in a way that guards against substitution attacks.
Specifically, classes that override -init
and conform to NSSecure
should use -decode
rather than -decode
.
Why is this important? Recall that NSCoding
is Foundation’s way of marshaling objects to be either archived on a file system, or copied to another address space. When -decode
is used to decode representations of objects into actual objects, there is no guarantee that the result of creating the object will be what was expected. If that representation is corrupted—specifically, in changing the target class (and thus designated initializer)—the application runs the risk of constructing unknown objects. Whether by malicious intent or an incidental coding error, this can cause serious problems.
It’s not an apples-to-apples comparison, but it’s somewhat similar to recent YAML exploit found in Rails.
For an XPC service, which is designed with security in mind, data integrity of this nature is especially important. It’s a safe bet that XPC will only wax influence in subsequent iOS and OS X releases, so it’s good to keep this all in mind.
Anyway, NSSecure
patches this vulnerability by establishing a contract for best practices. Now, decoding an object requires the class to be known ahead of time.
Whereas a standard, secure implementation of -init
might have a check like:
if let object = decoder.decode Object For Key("key") as? Some Class {
…
}
id obj = [decoder decode Object For Key:@"my Key"];
if (![obj is Kind Of Class:[My Class class]]) {
// fail
}
…an NSSecure
-conforming class would use:
let object = decoder.decode Object Of Class(Some Class.self, for Key: "key") as Some Class
id obj = [decoder decode Object Of Class:[My Class class]
for Key:@"my Key"];
Sometimes, a little API change makes all of the difference.
So now you know what’s up with NSSecure
. Perhaps not today, perhaps not tomorrow, but someday—you will probably need to implement NSSecure
. And when that day comes… you’ll be ready.
Stay safe, everyone.