Objective c 如何对id对象使用NSSecureCodeding

Objective c 如何对id对象使用NSSecureCodeding,objective-c,nssecurecoding,Objective C,Nssecurecoding,我正在创建一个链表,并使用容器对对象、下一个和上一个属性进行分组。与基础集合一样,我希望它能够实现 NSSECURCURE编码。声明如下: @interface ListContainer : NSObject <NSCopying, NSSecureCoding> @property (readonly, nonatomic) id object; @property (nonatomic) ListContainer * next; @property (nonatomic)

我正在创建一个链表,并使用容器对对象、下一个和上一个属性进行分组。与基础集合一样,我希望它能够实现<代码> NSSECURCURE编码。声明如下:

@interface ListContainer : NSObject <NSCopying, NSSecureCoding>

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

@end

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

我最后在Cocoa的邮件列表上发布了同样的问题,并进行了最有趣的讨论。其中一些亮点:

[…]对正常的东西做一个NSArray,比如NSString、NSNumber、encode 它,用DecodeObjectForClass解码,没有类。你会 在阵列上失败。将NSArray添加到允许的类和 .. 它起作用了。所以,你认为NSArray会盲目地解码任何这样的东西 它不再安全了

添加自定义类的对象,该自定义类 在阵列中实现安全编码,它将开始失败 再一次。NSArray和其他集合类型允许 已知的安全系统类型,如NSString,但在任何外部都会失败 那个[……]

在这一点上,我理解NSArray的行为并不像我预期的那样。安全编码似乎不再那么安全:

这似乎远非理想[…]事实上,它解码了一组 IMO认为,实现NSSecureCodeding的类有两个错误 理由[……]

1) 所包含的类实现NSSecureCoding的事实确实如此 这并不意味着我在期待它。[……]

2) 它限制了可以存储的类。[……]

在替换攻击中得到一个我不期望的类尤其可怕。显然,科科的承诺不同,但:

[…]如果直接在中使用NSArray()或其他集合类 您的编码,您需要检查返回的内容。他们是 “安全地”解码到苹果认为解码的程度 不会导致缓冲区溢出等,这就是你所能得到的 默认值。[……]

因此,不,
NSSecureCoding
不能保证容器的安全编码,或者至少不能保证类型检查,您必须自己做。即使是在Cocoa的原生数据结构中,也不像我最初设想的那样(我仍然认为这是有原因的)


所有这些道具都归罗兰·金所有。您可以看到完整的对话。

对对象进行编码时,可以使用NSStringFromClass和id对象的类名创建一个私有变量。当你解码它时,用这个来解码它。您甚至可以在NSDictionary中使用键/值对而不是单独的变量对其进行编码,解码时只需使用className键值来实例化适当的类,并使用适当的值来实例化键值。我确实想到了这一点。但是,如果我理解正确,安全编码用于防止当数据来自外部源(即在线)时实例化未知类型的对象。如果我这样做,我仍然允许攻击者实例化几乎任何对象,因为他们可以在该键中编码他们想要的任何类。他们称之为替代攻击。我想保护我的容器不受此影响。用于存储包含指定信息的密钥/值对的NSDictionary将使用安全编码机制存储在磁盘上,这意味着必须先解码对象属于NSDictionary类型的知识,然后才能显示键/值数据的知识。我不同意这一点。首先,因为不能保证它会留在磁盘上。编码对象通常用于通过导线发送。其次,因为它属于
NSDictionary
类型的知识是显式写在编码上的。我认为,这将是一个针对攻击的弱解决方案。破坏编码就如同我自己对一个列表进行编码并检查二进制结果一样简单,因为之前没有提到通过网络发送此信息,而且磁盘上的NSDictionary将使用安全编码,这意味着没有人能够识别该类是NSDictionary通过以下方式对NSDictionary进行编码:(第二,因为NSDictionary类型的知识是显式写在编码上的),而且这可以被自定义容器屏蔽。我要指出的是,还有其他许多方法可以解决这个问题,但这是苹果的实现。为什么不自己实现呢?当然,这绝对是一个选择。我只是假设
NSSecureCoding
会处理这样的情况,在所有这些都是针对
NSCoding
编写的:
这种技术可能是不安全的,因为当您可以验证类类型时,对象已经被构造,如果这是集合类的一部分,可能插入到对象图中
。这就是他们引入安全编码的方式,所以我猜这是错误的想法。苹果的实现是合乎逻辑的
NSArray
是一个通用容器。它无法检查对象类型,因为它与类型无关。如果您实现一个
id
对象列表,您将遇到相同的问题。当您打算接受任何内容时,如何在解码时测试类型?因此,最终的结果类似于
[aDecoder decodeObjectOfClass:[NSObject class]forKey:@“next”]这对您的目的毫无意义。此外,由于编码数据可以被攻击者操纵,因此在编码数据中存储对象类信息也毫无意义。因此,从“安全编码”中获得的是一个“安全”数组对象的承诺,而不是一个行为不端的对象。是的,我现在知道了:)当然,这是有意义的,但我仍然认为这些文件具有误导性。我不知道苹果公司是否为此实施了一些变通办法,所以我认为深入研究是个好主意。既然我知道了事实,我就明白了为什么和为什么不
- (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;
}