何时使用NSSecureCoding

时间:2013-06-25 15:45:15

标签: ios objective-c security nscoding nssecurecoding

我正在学习Apple在iOS 6中引入的NSSecureCoding协议。

根据我的理解,到目前为止,只要一个类对自身的实例进行编码/解码,就应该使用它,以防止替换攻击。

我想知道在其他情况下使用它是否合适。

具体来说,如果一个类通过编码/解码其实例变量来符合NSCoding,而不是整个实例,那么仍然建议实现NSSecureCoding吗?


修改

假设我有一个正在实现NSCoding的类,如下所示

- (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;
}

并且还假设没有涉及XPC。此类的实例将存储在磁盘上的plist中。

安全方面,与使用-decodeObjectOfClass:forKey:相比,使用是否有任何好处 -decodeObjectForKey:

3 个答案:

答案 0 :(得分:19)

  

具体来说,如果一个类通过编码/解码其实例变量来符合NSCoding,而不是整个实例,那么仍然建议实现NSSecureCoding吗?

这取决于您的应用程序的需求。对于任何旧的应用程序,使用普通的NSCoding将事物保存到磁盘是可以的,因为正在编写的信息和应用程序本身(本身不应该)是敏感的。但是,假设您是一家发行申请的银行。您可以选择将某些帐户信息或API密钥保留到磁盘,以便您可以与服务进行通信,验证用户的身份等。您可能不需要整个对象,但这并不重要。 NSCoder并不关心正在读取什么,只是它可以读取它并正确地完成它的工作。这是一个问题。

  

安全方面,使用-decodeObjectOfClass有什么好处:forKey:而不是-decodeObjectForKey:?

是的,非常如此。您依靠NSCoder序列化/反序列化对象(更不用说正确的对象)这一事实是一个巨大的攻击向量。一旦黑客以NSCoder使用的格式修改了信息(一种类似plist的结构,这是一种人类可读且非常容易制造的),那么就没有办法保证你得到的是你放入的内容。 NSCoder并不关心有人决定切换存档中包含的类,因此您正在重新构建恶意类的对象,运行时也不会。事实上,一个聪明的黑客会在应用程序中注入一个补丁,以确保反序列化的对象会引发某种未定义的状态(堆栈溢出),这可能会被用来潜在地利用整个应用程序。

decodeObjectOfClass:forKey:允许你强制NSCoder在反序列化方面变得更聪明,它会修补一个非常大的漏洞。这并不是说你应该从不在没有NSSecureCoding的情况下使用NSCoder,而是你必须聪明地了解你使用它的情况。

答案 1 :(得分:0)

当您调用decodeObjectForKey:来解码实例变量时,仍然会构建对象,然后才能验证其类类型(引入NSSecureCoding的原因)。

所以我假设这里仍然应用相同的规则,因此当您解码实例变量时,最好使用decodeObjectOfClass:forKey而不是decodeObjectForKey:

答案 2 :(得分:0)

以下是我阅读文档和NSHipsters帖子的感受。

您使用NSCoding将您的calsses变成二进制文件。这可以用于将数据拱起到磁盘,也可以用于进程间通信。归档到磁盘是相对安全的,但是,进程间通信存在风险,因为您可能不相信为您提供数据的源进程。

首先,如果你只是使用NSCoding来持久地将对象写入磁盘,那么你不必担心NSSecureCoding(但它很容易实现,见下文)

  

具体来说,如果一个类通过编码/解码其实例变量来符合NSCoding,而不是整个实例,那么仍然建议实现NSSecureCoding吗?

我不确定如何解码整个类的实例。通过解码归档器中的一些数据并对其执行某些操作来解码类。

- (id) initWithCoder:(NSCoder *)aDecoder 
{
   if (self = [super initWithCoder:aDecoder]) 
   {
       // Old way
       //obj myUnsecureObj = [aDecoder decodeObjectForKey:@"myKey"];

       // New way
       obj mySecureObj = [aDecoder decodeObjectOfClass:[MyClass class]
                                                forKey:@"myKey2"];

       // Use mySecureObj (e.g. save to an property / ivar)
   }
   return self;
}

+ (BOOL)supportsSecureCoding {
   return YES;
}