我正在学习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:
?
答案 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;
}