ラベル XPC の投稿を表示しています。 すべての投稿を表示
ラベル XPC の投稿を表示しています。 すべての投稿を表示

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の概要




[Mac] Lion から導入された XPC Services

2011年11月24日木曜日 | Published in | 0 コメント

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

Mac OS X 10.7 から XPC Services という仕組みが導入された。

リファレンスによれば XPC Services は単一のアプリケーション専用に利用できる軽量なヘルパーツール(lightweight helper tools)と定義されている。アプリのバンドル内に組み込んで実行時に利用するのでこの点を見れば通常のライブラリと似ている。ライブラリと大きく異なるのは、XPC Services はアプリとは独立して動作していて、XPC Services がクラッシュしてもアプリに影響を与えない点。XPC Services は launchd管理下にあり、起動・停止の他、クラッシュした場合の再起動まで面倒見てくれる。こう見ると XPC Services はOS上のプロセスに近い(プロセスなのかまでは調べきれなかったがプロセス間通信と説明されているのでそうなんだと思う。Mac OS X で何か軽量なプロセスが用意されているのだろうか。)。

アプリが XPC Services を利用する場合は XPC Services API を利用する。このAPIは GCDをサポートしている。


XPC Services を使う用途として次の2点が挙げられている。
  1. 安定性の向上 〜 XPC Services が落ちてもアプリには影響を与えない。
  2. セキュリティの向上 〜 XPC Services毎にアクセス制御を細かく設定できて、アクセス可能な範囲を本体のアプリとは分離できる。Sandboxでの利用が想定されている。

Xcode4.2では XPC作成用のテンプレートが用意されている。
XPCを利用するには XPCをテンプレートから作成し、アプリに組み込めば良い。

以下はテンプレートから生成されたコード。
static void TestService_peer_event_handler(xpc_connection_t peer, xpc_object_t event) 
{
 xpc_type_t type = xpc_get_type(event);
 if (type == XPC_TYPE_ERROR) {
  if (event == XPC_ERROR_CONNECTION_INVALID) {
   // The client process on the other end of the connection has either
   // crashed or cancelled the connection. After receiving this error,
   // the connection is in an invalid state, and you do not need to
   // call xpc_connection_cancel(). Just tear down any associated state
   // here.
  } else if (event == XPC_ERROR_TERMINATION_IMMINENT) {
   // Handle per-connection termination cleanup.
  }
 } else {
  assert(type == XPC_TYPE_DICTIONARY);
  // Handle the message.
 }
}

static void TestService_event_handler(xpc_connection_t peer) 
{
 // By defaults, new connections will target the default dispatch
 // concurrent queue.
 xpc_connection_set_event_handler(peer, ^(xpc_object_t event) {
  TestService_peer_event_handler(peer, event);
 });
 
 // This will tell the connection to begin listening for events. If you
 // have some other initialization that must be done asynchronously, then
 // you can defer this call until after that initialization is done.
 xpc_connection_resume(peer);
}

int main(int argc, const char *argv[])
{
 xpc_main(TestService_event_handler);
 return 0;
一種のサーバとして動作するのでイベントが来たときの処理を書いていく。


アプリは XPC Services のconnection系 APIを使い、アプリと XPC間で通信を行う。以下は connection.h で定義されている関数。
xpc_connection_cancel
xpc_connection_create
xpc_connection_get_asid
xpc_connection_get_context
xpc_connection_get_egid
xpc_connection_get_euid
xpc_connection_get_name
xpc_connection_get_pid
xpc_connection_resume
xpc_connection_send_message
xpc_connection_send_message_with_reply
xpc_connection_send_message_with_reply_sync
xpc_connection_set_context
xpc_connection_set_event_handler
xpc_connection_set_finalizer_f
xpc_connection_set_target_queue
xpc_connection_suspend


参考情報


Mac OS X Technology Overview: Kernel and Device Drivers Layer
XPCの紹介


Daemons and Services Programming Guide: Designing Daemons and Services

XPCの概要


Daemons and Services Programming Guide: Creating XPC Services
XPC Services の利用説明


API Reference: XPC Services API Reference


App Sandbox Design Guide: App Sandbox in Depth
Sandbox での XPCの利用について。


- - - -
単一アプリ専用のプロセスを動かして利用するというアイディアは面白い。Sandbox での安全性を高めるのが目的と思われるが、うまく使えば再利用性の高い簡易サーバプロセスとして利用できそう。


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