NSSecureCoding - セキュアなプロセス間通信への小さな布石

2013年4月20日土曜日 | Published in | 0 コメント

このエントリーをはてなブックマークに追加

NSSecureCoding という聞きなれないプロトコルが iOS6/OSX10.8から導入された。ここでいうCodingとはオブジェクトの永続化のプロコトル NSCodingのそれを指している。つまり NSSecureCoding はセキュアな NSCodingのこと。


NSSecureCodingの定義はクラスメソッドが1つあるだけ。
+ (BOOL)supportsSecureCoding;

使い方の前に何故この新しいプロコトルが導入されたかというと、現状のNSCodingだと不正なオブジェクトのロードを防げないから。
例えば -initWithCoder: の標準的な実装はこうなる。
id obj = [decoder decodeObjectForKey:@"myKey"];
if (![obj isKindOfClass:[MyClass class]]) {...fail...}
2行目でクラスチェックを行っているが実際には1行目でインスタンス化されていて既にその時点でクラスおよびインスタンスのイニシャライザは起動している。つまり現状では仮に不正なクラスが読み込み対象のファイルに紛れ込んでもその初動を防ぐことができない。

そこでNSCoderクラスに新しく -[NScoder decodeObjectOfClass:forKey:] が導入された。
NSCoder Class Reference

先程の2行の代わりに1行でチェックとデコードを同時に行う。
id obj = [decoder decodeObjectOfClass:[MyClass class]
            forKey:@"myKey"];
もし
(a)指定クラスがNSSecureCodingを実装している
(b)指定クラスとロードするクラスが一致する
のどちらかを満たさない場合は例外がスローされ、インスタンスの作成は行われない。これにより不正な振る舞いを防ぐことができる。なおこのチェックを有効にするには -[NScoder requiresSecureCoding]でYESを返すようにしておく必要がある(NOだとチェックは働かず実質 decodeObjectforKey:と変らない)。

この外部からのインスタンスロードのチェックに NSSecureCodingが使われる。このNSSecureCodingを実装するには次のどちらか2つの条件を満たす必要がある。
[a] initWithCoder: をオーバーライドしない
[b] initWithCoder: をオーバーライドする場合、decodeObjectOfClass:forKey: を使う
さらに + supportsSecureCodingをオーバーライドして、YESを返す必要がある。
この辺り、NScoderの条件と合わせると若干複雑な感じはする。

NSSecureCodingが導入されたのはXPC導入に伴うもので、iOSに関して言えばiOS6からXPCが導入された。このXPC導入に伴い、従来はアプリ内(1プロセス内)で完結していた動作がプロセス間での協調動作できるようになった。この為、従来の信頼できる自アプリ内の永続化データだけでなく、外部プロセスとの通信時に送られてくるデータの復元(decode)が必要になってきた。この時、攻撃者が何らかの方法で不正なクラス・インスタンスのデータを紛れ込ますことに成功した場合、従来の initWithCoder: ではチェックする手段が無い(※こういう攻撃方法を object substitution attacks と呼ぶらしい)。この対策としてNSSecureCodingを始めとする一連のAPIが導入された。

なお XPC Serviceを作ったり、直接アクセスできるのは今のところApple提供のライブラリだけ。一般開発者には公開されていない。このあたり次期iOS7でどうなるのかが非常に興味深い。


- - - -
今のところ一般開発者が使う理由があまり思いつかないが、XPCが公開された時には必須スタイルになるのかもしれない。



(参考)iOS6でのXPC利用


(参考)NSSecureCodingについて


(参考)XPCの概要




Responses

Leave a Response

人気の投稿(過去 30日間)