如何将 NSSecureCoding 与 id 对象一起使用

How to use NSSecureCoding with id objects

我正在创建链表并使用容器对对象、下一个和上一个属性进行分组。与 Foundation 集合一样,我希望它能够实现 NSSecureCoding。这是声明:

@interface ListContainer : NSObject <NSCopying, NSSecureCoding>

@property (readonly, nonatomic) id object;
@property (nonatomic) ListContainer * next;
@property (nonatomic) ListContainer * previous;

@end

在实施 - initWithCoder: 方法时,我突然想到我不知道要为对象使用什么 class:

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];

    if (self) {

        _object = [aDecoder decodeObjectOfClass:<#(__unsafe_unretained Class)#> forKey:@"object"];

        BOOL nextIsNil = [aDecoder decodeBoolForKey:@"nextIsNil"];

        if (!nextIsNil) {

            // Decode next
            _next = [aDecoder decodeObjectOfClass:[ListContainer class] forKey:@"next"];

            if (_next == nil) {
                return nil;
            }

            // Link the nodes manually to prevent infinite recursion
            self.next.previous = self;
        }
    }

    return self;
}

我应该改用 -decodeObjectForKey: 吗?它仍然是安全编码吗?

我最终将相同的问题发布到 Cocoa 的邮件列表,并且发生了最有趣的讨论。一些亮点:

[...] Make an NSArray of normal stuff, like NSString, NSNumber, encode it, decode it with decodeObjectForClasses, with no classes. You’ll fail on the array. Add the NSArray to the list of allowed classes and .. it works. So, you think, NSArray will blindly decode anything so it’s no-longer secure.

Add an object of a custom class which implements secure coding into the array, and it will start failing again. NSArray, and the other collection types, allow elements of known secure system types, like NSString, but fail at anything outside that. [...]

此时我了解到 NSArray 的行为与我预期的不同。安全编码似乎不再那么安全了:

This seems far from ideal [...] The fact that it decodes a set of classes known to implement NSSecureCoding is wrong, IMO, for two reasons [...]

1) The fact that the contained class implements NSSecureCoding does not mean that I'm expecting it. [...]

2) It limits the classes which can be stored. [...]

在替换攻击中得到一个我没有预料到的 class 尤其可怕。显然 Cocoa 的承诺是不同的,但是:

[...] if you use NSArray() or other collection classes directly in your coding, you need to check what you got back. They are ‘securely’ decoded to the extent that Apple believes decoding them will not result in a buffer overflow etc, that’s all you get by default. [...]

所以,不,NSSecureCoding 不能保证容器的安全编码,或者至少不能保证类型检查,您必须自己做。甚至在 Cocoa 的本机数据结构中也不如我最初假设的那样(有理由,我仍然这么认为)。

所有的努力都归功于 Roland King。你可以看到完整的对话 here.