Sunday, November 8, 2015

The Java Deserialization Bug and NSSecureCoding

Charles Miller:

The problem, described in the talk the exploit was first raised in — Marshalling Pickles — is that arbitrary object deserialization (or marshalling, or un-pickling, whatever your language calls it) is inherently unsafe, and should never be performed on untrusted data.

[…]

This means that if there is any object reachable from your runtime that declares itself serializable and could be fooled into doing something bad by malicious data, then it can be exploited through deserialization. This is a mind-bogglingly enormous amount of potentially vulnerable and mostly un-audited code.

In Cocoa land, this is why we have NSSecureCoding. Some things to be aware of:

Update (2015-11-10): Paul Kim:

Even if you don’t call -decodeObject:… in your -initWithCoder: you still have to implement +supportsSecureCoding and return YES in your class, even if a superclass already did it.

[…]

Objects like NSPredicate and NSSortDescriptor can take in key paths or selectors making them potentially unsafe. As a result, they are disabled after being securely decoded. To re-enable them, you have to call -allowEvaluation (presumably after doing some sort of check).

2 Comments RSS · Twitter

NSCoder got NSError-ish methods in 10.11:

https://developer.apple.com/library/mac/releasenotes/Foundation/RN-Foundation/#10_11Coder (Unfortunately, I don't think this anchor actually works)

and for Swift, there's this in NSCoder.h:

- (nullable id)decodeTopLevelObjectAndReturnError:(NSError **)error NS_AVAILABLE(10_11, 9_0) NS_SWIFT_UNAVAILABLE("Use 'decodeTopLevelObject() throws' instead");

@aaron Thanks for reminding me! For some reason, that’s not in the regular documentation. Here’s the full set of new NSCoder error methods:

- (nullable id)decodeTopLevelObjectAndReturnError:(NSError **)error;
- (nullable id)decodeTopLevelObjectForKey:(NSString *)key 
                                    error:(NSError **)error;
- (nullable id)decodeTopLevelObjectOfClass:(Class)aClass
                                    forKey:(NSString *)key
                                     error:(NSError **)error;
- (nullable id)decodeTopLevelObjectOfClasses:(nullable NSSet<Class> *)classes
                                      forKey:(NSString *)key
                                       error:(NSError **)error;
- (void)failWithError:(NSError *)error;

And NSKeyedUnarchiver now has:

+ (nullable id)unarchiveTopLevelObjectWithData:(NSData *)data
                                         error:(NSError **)error;

There’s still no convenience method for secure unarchiving.

Leave a Comment