5

I have an Objective-C protocol that requires conformance to NSSecureCoding:

@protocol MyProtocol <NSObject, NSSecureCoding>
…
@end

I have a parent object that stores a reference to an object conforming to MyProtocol, and I would like the parent object to also conform to NSSecureCoding. When I try this:

required init?(coder aDecoder: NSCoder) {

    if let childObject = aDecoder.decodeObject(of: MyProtocol.self, forKey: "childObject") {
        self. childObject = childObject
    } else {
        return nil
    }
}

I get the error: 'decodeObject(of:forKey:)' is unavailable in Swift: use generic 'decodeObjectOfClass(_:forKey:)'.

Is there any way to use NSSecureCoding if you don't know the specific class of the object you encoded?

Jeff V
  • 571
  • 1
  • 5
  • 17

1 Answers1

7

The entire point of NSSecureCoding is to prevent this use case. If you do not know the class you are decoding, then an attacker can trick you into decoding into a class that behaves differently than the one you expected for a given method (called a "substitution attack"). This was a technique used to attack systems, and NSSecureCoding was developed to thwart it.

Even if that weren't the case, it's not possible to construct an object of protocol type. The runtime would have no way to know how much memory to allocate for instance variables.

In order to conform to NSSecureCoding, you must know the precise classes of all child objects.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • I thought I heard NSCoding will be deprecated, in favor of NSSecureCoding, in the near future in one of the WWDC sessions I just watched. If true, what could I do in this case? – Jeff V Jun 08 '18 at 01:42
  • 2
    @JeffV That’s not true: there are no intentions of deprecating `NSCoding`. You can disable secure coding when unarchiving; the best thing to do is to, over time, where possible, migrate this data forward to a scheme which does allow you to decode with secure coding enabled. – Itai Ferber Jun 08 '18 at 03:15
  • 1
    You can do this by finding a way to pass that type information to your type from the outside; one way to do this is to reuse what is currently in the unarchiver’s `allowedClasses` list to decode. Someone could then request to `decodeObject(ofClasses: [.self, .self], forKey: ...)` in the same way that they would need to do for `NSArray` and other collections. If someone decoding your type would be able to indicate what child object type they expect, I can give a more illustrative example of this. – Itai Ferber Jun 08 '18 at 03:21