次の方法で共有


Xamarin.Mac アプリのサンドボックス化

この記事は、App Store でリリースするための Xamarin.Mac アプリケーションのサンドボックス化について説明しています。 また、サンドボックスに含めるすべての要素 (コンテナー ディレクトリ、エンタイトルメント、ユーザーが決定するアクセス許可、特権の分離、カーネルの適用など) について説明しています。

概要

Xamarin.Mac アプリケーションで C# と .NET を使う場合、Objective-C または Swift を使う場合と同じようにアプリケーションをサンドボックス化できます。

実行中のアプリの例

この記事では、Xamarin.Mac アプリケーションでのサンドボックス化の基本操作と、コンテナー ディレクトリ、エンタイトルメント、ユーザーが決定するアクセス許可、特権の分離、カーネルの適用など、サンドボックス化に含まれるすべての要素について説明します。 この記事で使う主要な概念と手法については、まず Hello Mac の記事、特に「Xcode と Interface Builder の概要」と「Outlet と Action」のセクションを参照することを強くお勧めします。

Xamarin.Mac Internals ドキュメントの C# クラス/メソッドの Objective-C への公開に関するセクションも参照することをお勧めします。C# クラスを Objective-C オブジェクトと UI 要素に結び付けるために使われる Register および Export 属性について説明されています。

アプリ サンドボックスの概要

アプリ サンドボックスは、アプリケーションがシステム リソースに対して持つアクセスを制限することで、Mac 上で実行されている悪意のあるアプリケーションが引き起こす可能性のある損害に対する強力な防御を提供します。

サンドボックス化されていないアプリケーションには、そのアプリを実行しているユーザーの完全な権限があり、ユーザーが実行できるすべてのことにアクセスすることや実行することができます。 アプリ (または使っているフレームワーク) にセキュリティ ホールが含まれている場合、ハッカーがそれらの弱点を悪用し、アプリを使って、それが実行されている Mac を制御する可能性があります。

サンドボックス アプリは、アプリケーションごとにリソースに対するアクセスを制限することで、ユーザーのマシン上で実行されているアプリケーションの盗難、破損、または悪意のある意図に対する防御線を提供します。

アプリ サンドボックスは、macOS に組み込まれた (カーネル レベルで適用される) アクセス制御テクノロジであり、次の 2 つの戦略が用意されています。

  1. アプリ サンドボックスを使うと、開発者はアプリケーションが OS と対話する "方法" を記述できます。これにより、ジョブの実行に必要なアクセス権のみが付与され、それ以上は付与されません。
  2. アプリ サンドボックスを使うと、ユーザーは、[開く] と [保存] のダイアログ ボックス、ドラッグ アンド ドロップ操作、その他の一般的なユーザー操作を介して、システムに対するさらなるアクセス権をシームレスに付与することができます。

アプリ サンドボックスの実装の準備

この記事で詳しく説明するアプリ サンドボックスの要素は次のとおりです。

  • コンテナー ディレクトリ
  • 権利
  • ユーザーが決定するアクセス許可
  • 特権の分離
  • カーネルの適用

これらの詳細を理解したら、Xamarin.Mac アプリケーションにアプリ サンドボックスを導入する計画を作成できるようになります。

まず、アプリケーションがサンドボックス化に適しているかどうかを判断する必要があります (ほとんどのアプリケーションは適しています)。 次に、API の非互換性を解決し、アプリ サンドボックスのどの要素が必要かを判断する必要があります。 最後に、アプリケーションの防御レベルを最大化するために特権の分離を使うことを検討します。

アプリ サンドボックスを導入する場合、アプリケーションが使うファイル システムの場所の一部は異なります。 特に、アプリケーションには、アプリケーション サポート ファイル、データベース、キャッシュ、ユーザー ドキュメントではないその他のファイルに使われるコンテナー ディレクトリがあります。 macOS と Xcode は両方とも、このような種類のファイルを従来の場所からコンテナーに移行するためのサポートを提供します。

サンドボックスのクイック スタート

このセクションでは、アプリ サンドボックスを始める方法の一例として、Web ビュー (特に要求されない限り、サンドボックスで制限されたネットワーク接続が必要です) を使う単純な Xamarin.Mac アプリを作成します。

アプリケーションが実際にサンドボックス化されていることを確認し、一般的なアプリ サンドボックス エラーのトラブルシューティングと解決方法について説明します。

Xamarin.Mac プロジェクトの作成

以下の手順でサンプル プロジェクトを作成しましょう。

  1. Visual Studio for Mac を起動し、[新しいソリューション] リンクをクリックします。

  2. [新しいプロジェクト] ダイアログ ボックスで、[Mac]>[アプリ]>[Cocoa アプリ] を選びます。

    新しい Cocoa アプリの作成

  3. [次へ] ボタンをクリックし、プロジェクト名に「MacSandbox」と入力して、[作成] ボタンをクリックします。

    アプリ名の入力

  4. Solution PadMain.storyboard ファイルをダブルクリックし、Xcode で編集するために開きます。

    メイン ストーリーボードの選択

  5. Web ビューをウィンドウにドラッグし、コンテンツ領域に合わせてサイズを調整し、ウィンドウに合わせて拡大および縮小するように設定します。

    Web ビューの追加

  6. webView という Web ビューのアウトレットを作成します。

    新しいアウトレットの作成

  7. Visual Studio for Mac に戻り、Solution Pad 内の ViewController.cs ファイルをダブルクリックして編集用に開きます。

  8. 次の using ステートメントを追加します: using WebKit;

  9. ViewDidLoad メソッドを次のようにします。

    public override void AwakeFromNib ()
    {
        base.AwakeFromNib ();
        webView.MainFrame.LoadRequest(new NSUrlRequest(new NSUrl("http://www.apple.com")));
    }
    
  10. 変更を保存します。

アプリケーションを実行し、次のように Apple Web サイトがウィンドウに表示されることを確認します。

アプリの実行例の表示

アプリの署名とプロビジョニング

アプリ サンドボックスを有効にする前に、まず Xamarin.Mac アプリケーションのプロビジョニングと署名を行う必要があります。

次の操作を行います。

  1. Apple Developer ポータルにログインします。

    Apple 開発者ポータルへのログイン

  2. [Certificates, Identifiers & Profiles] を選びます。

    [Certificates, Identifiers & Profiles] を選択する

  3. [Mac Apps][Identifiers] を選びます。

    識別子の選択

  4. アプリケーションの新しい ID を作成します。

    新しいアプリ ID の作成

  5. [Provisioning Profiles] で、[Development] を選びます。

    開発の選択

  6. 新しいプロファイルを作成し、[Mac App Development] を選びます。

    新しいプロファイルの作成

  7. 先ほど作成したアプリ ID を選びます。

    アプリ ID の選択

  8. このプロファイルの開発者を選びます。

    開発者の追加

  9. このプロファイルのコンピューターを選びます。

    許可するコンピューターの選択

  10. プロファイルに名前を付けます。

    プロファイルに名前を付けます

  11. [完了] ボタンをクリックします。

重要

場合によっては、必要に応じて新しいプロビジョニング プロファイルを Apple の Developer ポータルから直接ダウンロードし、ダブルクリックしてインストールします。 また、新しいプロファイルにアクセスするには、必要に応じて Visual Studio for Mac を停止して再起動します。

次に、新しいアプリ ID とプロファイルを開発マシンに読み込む必要があります。 次の操作を行います。

  1. Xcode を起動し、[Xcode] メニューから [Preferences] を選びます。

    Xcode でのアカウントの編集

  2. [View Details] ボタンをクリックします。

    [詳細の表示] ボタンをクリックする

  3. [Refresh] ボタン (左下隅) をクリックします。

  4. [Done] ボタンをクリックします。

次に、Xamarin.Mac プロジェクトで新しいアプリ ID とプロビジョニング プロファイルを選ぶ必要があります。 次の操作を行います。

  1. Solution PadInfo.plist ファイルをダブルクリックして編集用に開きます。

  2. [Bundle Identifier] が先ほど作成したアプリ ID と一致していることを確認します (例: com.appracatappra.MacSandbox)。

    バンドル識別子の編集

  3. 次に、Entitlements.plist ファイルをダブルクリックし、[iCloud Key-Value Store][iCloud Containers] のすべてが、先ほど作成したアプリ ID と一致していることを確認します (例: com.appracatappra.MacSandbox)。

    Entitlements.plist ファイルの編集

  4. 変更を保存。

  5. Solution Pad でプロジェクト ファイルをダブルクリックし、編集の [Options] を開きます。

    ソリューションのオプションを編集する

  6. [Mac 署名] を選び、[アプリケーション バンドルに署名します][インストーラー パッケージに署名します] をオンにします。 [プロビジョニング プロファイル] で、先ほど作成したプロファイルを選びます。

    プロビジョニング プロファイルの設定

  7. [完了] ボタンをクリックします。

重要

Xcode によってインストールされた新しいアプリ ID とプロビジョニング プロファイルが認識されるように、必要に応じて Visual Studio for Mac を終了して再起動します。

プロビジョニングに関する問題のトラブルシューティング

この時点で、アプリケーションを実行し、すべてが正しく署名されていること、プロビジョニングされていることを確認する必要があります。 アプリが以前と同じように動作している場合は、すべて問題ありません。 エラーが発生した場合、次のようなダイアログ ボックスが表示されることがあります。

プロビジョニングの問題のダイアログの例

プロビジョニングと署名に関する問題の最も一般的な原因は次のとおりです。

  • アプリ バンドル ID が、選んだプロファイルのアプリ ID と一致しません。
  • 開発者 ID が、選んだプロファイルの開発者 ID と一致しません。
  • テスト対象の Mac の UUID が、選んだプロファイルの一部として登録されていません。

問題が発生した場合は、Apple Developer ポータルで問題を修正し、Xcode でプロファイルを更新し、Visual Studio for Mac でクリーン ビルドを実行します。

アプリ サンドボックスを有効にする

プロジェクト オプションのチェックボックスをオンにして、アプリ サンドボックスを有効にします。 次の操作を行います。

  1. Solution Pad で、Entitlements.plist ファイルをダブルクリックして開き、編集します。

  2. [エンタイトルメントを有効にする][アプリ サンドボックスを有効にする] の両方をオンにします。

    権利の編集とサンドボックスの有効化

  3. 変更を保存。

この時点で、アプリ サンドボックスは有効になっていますが、Web ビューに必要なネットワーク アクセスは提供されていません。 ここでアプリケーションを実行すると、空白のウィンドウが表示されます。

ブロックされている Web アクセスの表示

アプリがサンドボックス化されていることの確認

リソースのブロック動作とは別に、Xamarin.Mac アプリケーションが正常にサンドボックス化されているかどうかを確認するには、主に 3 つの方法があります。

  1. Finder で、~/Library/Containers/ フォルダーの内容を確認します。アプリがサンドボックス化されている場合は、アプリのバンドル識別子のような名前のフォルダーがあります (例: com.appracatappra.MacSandbox)。

    アプリのバンドルを開く

  2. システムのアクティビティ モニターにはアプリがサンドボックスとして表示されます。

    • アクティビティ モニターを起動します (/Applications/Utilities の下)。
    • [表示]>[列] を選び、[サンドボックス] メニュー項目がオンになっていることを確認します。
    • アプリケーションの [サンドボックス] 列に Yes と表示されていることを確認します。

    アクティビティ モニターでアプリを確認する

  3. アプリ バイナリがサンドボックス化されていることを確認します。

    • ターミナル アプリを起動します。
    • アプリケーションの bin ディレクトリに移動します。
    • 次のコマンドを発行します: codesign -dvvv --entitlements :- executable_path (executable_path はアプリケーションのパスです)。

    コマンド ラインでアプリを確認する

サンドボックス アプリのデバッグ

デバッガーは TCP 経由で Xamarin.Mac アプリに接続します。つまり、サンドボックスを有効にすると、既定ではアプリに接続できなくなります。そのため、適切なアクセス許可を有効にせずにアプリを実行しようとすると、エラー "デバッガーに接続できません" を受け取ります。

必要なオプションの設定

[送信ネットワーク接続を許可する (クライアント)] アクセス許可はデバッガーに必要なものであり、これを有効にすると通常どおりにデバッグできるようになります。 これなしではデバッグできないため、msbuildCompileEntitlements ターゲットを更新し、デバッグ ビルド専用のサンドボックス化されたアプリのエンタイトルメントにそのアクセス許可を自動的に追加しました。 リリース ビルドでは、エンタイトルメント ファイルに指定されたエンタイトルメントを変更せずに使う必要があります。

アプリ サンドボックス違反の解決

アプリ サンドボックス違反が起こるのは、サンドボックス Xamarin.Mac アプリケーションが明示的に許可されていないリソースにアクセスしようとした場合です。 たとえば、Web ビューは Apple Web サイトを表示できなくなります。

アプリ サンドボックス違反の最も一般的な原因は、Visual Studio for Mac で指定されたエンタイトルメント設定がアプリケーションの要件と一致しない場合に発生します。 もう一度、例に戻ります。ネットワーク接続エンタイトルメントがないため、Web ビューが機能しません。

アプリ サンドボックス違反の検出

Xamarin.Mac アプリケーションでアプリ サンドボックス違反が発生していると思われる場合、問題を最も簡単に検出するには、コンソール アプリを使います。

次の操作を行います。

  1. 問題のアプリをコンパイルし、Visual Studio for Mac から実行します。

  2. (/Applications/Utilties/ から) コンソール アプリケーションを開きます。

  3. サイドバーの [すべてのメッセージ] を選び、検索に「sandbox」と入力します。

    コンソールでのサンドボックスの問題の例

上記のサンプル アプリでは、アプリ サンドボックスがあることで、カーネルが network-outbound トラフィックをブロックしていることがわかります。これは、その権限を要求していないためです。

エンタイトルメントによるアプリ サンドボックス違反の修正

アプリ サンドボックス違反を見つける方法を確認したので、次はアプリケーションのエンタイトルメントを調整することで解決する方法を見てみましょう。

次の操作を行います。

  1. Solution Pad で、Entitlements.plist ファイルをダブルクリックして開き、編集します。

  2. [エンタイトルメント] セクションで、[送信ネットワーク接続を許可する (クライアント)] チェックボックスをオンにします。

    権利の編集

  3. 変更をアプリケーションに保存します。

サンプル アプリに対して上記の操作を実行し、ビルドして実行すると、Web コンテンツは期待どおりに表示されるようになります。

アプリ サンドボックスの詳細

アプリ サンドボックスが備えるアクセス制御メカニズムは少数で、理解しやすいものです。 ただし、アプリ サンドボックスが各アプリに導入される方法は独自であり、アプリの要件に基づいてます。

Xamarin.Mac アプリケーションを悪意のあるコードによる悪用から保護するために最大限の努力を行った場合、アプリとシステムの相互作用を制御するには、アプリ (またはそれが使うライブラリやフレームワークのいずれか) に脆弱性が 1 つだけあれば十分です。

アプリ サンドボックスは、アプリケーションとシステム間の意図したやり取りを指定できるようにすることで、乗っ取りを防ぐ (または結果として生じる可能性のある損害を制限する) ように設計されました。 システムは、アプリケーションがジョブを実行するために必要なリソースに対するアクセスのみを付与し、それ以上は付与しません。

アプリ サンドボックス用に設計するときは、最悪のシナリオを想定して設計します。 アプリケーションが悪意のあるコードによって侵害された場合、アクセスはアプリケーションのサンドボックス内のファイルとリソースのみに制限されます。

エンタイトルメントとシステム リソースのアクセス

前述のように、サンドボックス化されていない Xamarin.Mac アプリケーションには、アプリを実行しているユーザーの完全な権限とアクセスが付与されます。 悪意のあるコードによって侵害された場合、保護されていないアプリは、敵対的な動作のエージェントとして機能し、広範囲に損害を与える可能性があります。

アプリ サンドボックスを有効にすると、最小限の特権セットを除くすべての特権が削除されます。その後、Xamarin.Mac アプリのエンタイトルメントを使って、必要に応じて特権を再度有効にします。

アプリケーションのアプリ サンドボックス リソースを変更するには、その Entitlements.plist ファイルを編集し、エディターのドロップダウン ボックスで必要な権限を確認または選択します。

権利の編集

コンテナー ディレクトリとファイル システムのアクセス

Xamarin.Mac アプリケーションにアプリ サンドボックスを導入すると、次の場所にアクセスできるようになります。

  • アプリ コンテナー ディレクトリ - 初回実行時に、OS によって、それのみがアクセスできる特殊な "コンテナー ディレクトリ" が作成されます。ここにすべてのリソースが格納されます。 アプリには、このディレクトリへの完全な読み取りおよび書き込みアクセス権が付与されます。
  • アプリ グループ コンテナー ディレクトリ - 同じグループ内のアプリ間で共有される 1 つ以上の "グループ コンテナー" に対するアクセスをアプリに付与できます。
  • ユーザー指定ファイル - ユーザーが明示的に開いた、またはアプリケーションにドラッグ アンド ドロップしたファイルに対するアクセスを、アプリケーションは自動的に取得します。
  • 関連項目 - 適切なエンタイトルメントがあれば、アプリケーションは名前が同じで拡張子が異なるファイルにアクセスできます。 たとえば、.txt ファイルと .pdf の両方として保存されているドキュメントです。
  • 一時ディレクトリ、コマンドライン ツール ディレクトリ、特定の誰でも読み取り可能な場所 - システムの指定に従い、他の適切に定義された場所にあるファイルに対して、アプリはさまざまなレベルのアクセス権を持ちます。

アプリ コンテナー ディレクトリ

Xamarin.Mac アプリケーションのアプリ コンテナー ディレクトリには次の特徴があります。

  • ユーザーのホーム ディレクトリ (通常は ~Library/Containers) 内の非表示の場所にあり、アプリケーション内の NSHomeDirectory 関数 (後述) を使ってアクセスできます。 ホーム ディレクトリ内にあるため、各ユーザーはアプリの独自のコンテナーを取得します。
  • コンテナー ディレクトリとそのすべてのサブ ディレクトリおよびファイルに対して、アプリには無制限の読み取りおよび書き込みアクセス権があります。
  • macOS のパス検索 API のほとんどは、アプリのコンテナーに対して相対的です。 たとえば、コンテナーには独自の Library (NSLibraryDirectory 経由でアクセス)、Application SupportPreferences サブディレクトリがあります。
  • macOS は、コード署名を介して、アプリとそのコンテナー間の接続を確立し、適用します。 別のアプリがそのバンドル識別子を使ってアプリになりすまそうとしても、コード署名があるため、コンテナーにアクセスすることはできません。
  • コンテナーはユーザーが生成したファイル用ではありません。 そうではなく、データベース、キャッシュ、その他の特定の種類のデータなど、アプリケーションが使うファイルが対象です。
  • shoebox 型のアプリ (Apple の写真アプリなど) の場合、ユーザーのコンテンツはコンテナーに格納されます。

重要

残念ながら、Xamarin.Mac は (Xamarin.iOS とは異なり) まだ 100% の API に対応していないため、NSHomeDirectory API は現在のバージョンの Xamarin.Mac にマップされていません。

一時的な回避策として、次のコードを使用できます。

[System.Runtime.InteropServices.DllImport("/System/Library/Frameworks/Foundation.framework/Foundation")]
public static extern IntPtr NSHomeDirectory();

public static string ContainerDirectory {
    get {
        return ((NSString)ObjCRuntime.Runtime.GetNSObject(NSHomeDirectory())).ToString ();
        }
}

アプリ グループ コンテナー ディレクトリ

Mac macOS 10.7.5 (以降) から、アプリケーションは com.apple.security.application-groups エンタイトルメントを使って、グループ内のすべてのアプリケーションに共通の共有コンテナーにアクセスできます。 この共有コンテナーは、データベースや他の種類のサポート ファイル (キャッシュなど) といったユーザー向けではないコンテンツに使用できます。

グループ コンテナーは、各アプリのサンドボックス コンテナー (グループの一部である場合) に自動的に追加され、~/Library/Group Containers/<application-group-id> に保存されます。 グループ ID は、開発チーム ID とピリオドで始まる "必要があります"。次に例を示します。

<team-id>.com.company.<group-name>

詳細については、Apple の「Entitlement Key Reference (エンタイトルメント キー リファレンス)」のアプリケーション グループへのアプリケーションの追加に関する記事を参照してください。

アプリ コンテナーの外部にある Powerbox とファイル システムのアクセス

サンドボックス Xamarin.Mac アプリケーションは、次の方法でコンテナーの外部にあるファイル システムの場所にアクセスできます。

  • ユーザーの特定の指示 ([開く] と [保存] のダイアログや、ドラッグ アンド ドロップなどのその他の方法を介して)。
  • 特定のファイル システムの場所 (/bin/usr/lib など) に対するエンタイトルメントの使用。
  • ファイル システムの場所が、誰でも読み取り可能な特定のディレクトリ (共有など) 内にある場合。

Powerbox は、ユーザーと対話してサンドボックス Xamarin.Mac アプリのファイル アクセス権を拡張する macOS セキュリティ テクノロジです。 Powerbox には API がありませんが、アプリが NSOpenPanel または NSSavePanel を呼び出すと透過的にアクティブにされます。 Powerbox のアクセスは、Xamarin.Mac アプリケーションに設定したエンタイトルメントを介して有効になります。

サンドボックス アプリで [開く] または [保存] ダイアログを表示すると、ウィンドウは (AppKit ではなく) Powerbox によって表示されるため、ユーザーがアクセスできるファイルまたはディレクトリにアクセスできます。

ユーザーが [開く] または [保存] ダイアログからファイルまたはディレクトリを選ぶと (またはアプリのアイコンにドラッグすると)、Powerbox により、関連付けられたパスがアプリのサンドボックスに追加されます。

さらに、システムにより、サンドボックス アプリに対して次のことが自動的に許可されます。

  • システム入力方法への接続。
  • [サービス] メニューからユーザーが選んだサービスを呼び出します (サービス プロバイダーによって "サンドボックス アプリに対して安全" とマークされているサービスのみ)。
  • [最近使ったファイルを開く] メニューからユーザーが選んだファイルを開きます。
  • 他のアプリケーション間でコピーと貼り付けを使います。
  • 次の誰でも読み取り可能な場所からファイルを読み取ります。
    • /bin
    • /sbin
    • /usr/bin
    • /usr/lib
    • /usr/sbin
    • /usr/share
    • /System
  • NSTemporaryDirectory によって作成されたディレクトリ内のファイルの読み取りと書き込みを行います。

既定では、サンドボックス Xamarin.Mac アプリによって開かれた、または保存されたファイルは、アプリが終了するまでアクセスできます (アプリの終了時にファイルがまだ開いていた場合を除く)。 開いているファイルは、次回アプリを起動したときに、macOS の再開機能を介してアプリのサンドボックスに自動的に復元されます。

Xamarin.Mac アプリのコンテナーの外部にあるファイルに永続性を持たせるには、セキュリティスコープ ブックマークを使います (後述)。

アプリ サンドボックスを使うと、アプリは、同じファイル名で拡張子が異なる関連項目にアクセスできます。 この機能には 2 つの部分があります。a) アプリの Info.plst ファイル内の関連する拡張子の一覧、b) アプリがこのようなファイルに対して何を行うかをサンドボックスに伝えるコード。

これが意味を持つシナリオは 2 つあります。

  1. アプリは、ファイルの異なるバージョン (拡張子が新しいもの) を保存できる必要があります。 たとえば、.txt ファイルを .pdf ファイルにエクスポートする場合です。 この状況に対処するには、NSFileCoordinator を使ってファイルにアクセスする必要があります。 まず WillMove(fromURL, toURL) メソッドを呼び出し、ファイルを新しい拡張子に移動してから、ItemMoved(fromURL, toURL) を呼び出します。
  2. アプリは、ある拡張子を持つメイン ファイルと、異なる拡張子を持つ複数のサポート ファイルを開く必要があります。 たとえば、ムービーと字幕ファイルです。 NSFilePresenter を使ってセカンダリ ファイルにアクセスします。 メイン ファイルを PrimaryPresentedItemURL プロパティに指定し、セカンダリ ファイルを PresentedItemURL プロパティに指定します。 メイン ファイルを開いたら、NSFileCoordinator クラスの AddFilePresenter メソッドを呼び出してセカンダリ ファイルを登録します。

どちらのシナリオでも、アプリの Info.plist ファイルで、アプリが開くことができるドキュメントの種類を宣言する必要があります。 どのファイルの種類でも、NSIsRelatedItemType (値は YES) を CFBundleDocumentTypes 配列のエントリに追加します。

サンドボックス アプリの [開く] および [保存] ダイアログの動作

サンドボックス Xamarin.Mac アプリから NSOpenPanelNSSavePanel を呼び出す場合、次の制限が適用されます。

  • [OK] ボタンをプログラムで呼び出すことはできません。
  • NSOpenSavePanelDelegate でのユーザーの選択をプログラムで変更することはできません。

さらに、次の継承の変更が行われます。

  • サンドボックス以外のアプリ - NSOpenPanel NSSavePanel``NSPanel``NSWindow``NSResponder``NSObject``NSOpenPanel``NSSavePanel``NSObject``NSOpenPanel``NSSavePanel

セキュリティ スコープ ブックマークと永続的なリソースのアクセス

前述のように、サンドボックス Xamarin.Mac アプリケーションは、(PowerBox が提供する) ユーザーの直接操作によって、コンテナーの外部にあるファイルやリソースにアクセスできます。 ただし、これらのリソースに対するアクセスは、アプリの起動またはシステムの再起動後も自動的に維持されるわけではありません。

セキュリティスコープ ブックマークを使うと、サンドボックス Xamarin.Mac アプリケーションはユーザーの意図を保持し、アプリの再起動後も特定のリソースに対するアクセスを維持できます。

セキュリティスコープ ブックマークの種類

セキュリティスコープ ブックマークと永続的なリソース アクセスを使う場合、次の 2 つの sistine のユース ケースがあります。

  • アプリスコープ ブックマークで、ユーザー指定ファイルまたはフォルダーへの永続的なアクセスを提供します。

    たとえば、サンドボックス Xamarin.Mac アプリケーションで (NSOpenPanel を使って) 編集対象の外部ドキュメントを開くことを許可する場合、アプリでアプリスコープ ブックマークを作成して、今後も同じファイルに再度アクセスできるようにすることができます。

  • ドキュメントスコープ ブックマークで、サブファイルに対する永続的なアクセスを特定のドキュメントに提供します。

たとえば、後で 1 つのムービーに結合される個々の画像、ビデオ クリップ、サウンド ファイルにアクセスできるプロジェクト ファイルを作成するビデオ編集アプリです。

ユーザーが (NSOpenPanel を使って) リソース ファイルをプロジェクトにインポートすると、アプリはプロジェクトに保存されている項目に対してドキュメントスコープ ブックマークを作成し、アプリが常にそのファイルにアクセスできるようにします。

ドキュメントスコープ ブックマークは、ブックマーク データとドキュメント自体を開くことができる任意のアプリケーションによって解決できます。 これは移植性をサポートしているため、ユーザーがプロジェクト ファイルを別のユーザーに送信し、すべてのブックマークをそのユーザーに対しても同様に機能させることができます。

重要

ドキュメントスコープ ブックマークは、フォルダーではなく 1 つのファイル "のみ" を指すことができます。また、システムが使う場所 (/private/Library など) にそのファイルを配置することはできません。

セキュリティスコープ ブックマークの使用

いずれかの種類のセキュリティスコープ ブックマークを使うには、以下の手順を実行する必要があります。

  1. セキュリティスコープ ブックマークを使う必要がある Xamarin.Mac アプリで適切なエンタイトルメントを設定する - アプリスコープ ブックマークの場合は、com.apple.security.files.bookmarks.app-scope エンタイトルメント キーを true に設定します。 ドキュメントスコープ ブックマークの場合は、com.apple.security.files.bookmarks.document-scope エンタイトルメント キーを true に設定します。
  2. セキュリティスコープ ブックマークを作成する - ユーザーが (たとえば、NSOpenPanel を使って) アクセスを提供し、アプリが永続的にアクセスする必要があるファイルまたはフォルダーに対してこれを行います。 ブックマークを作成するには、NSUrl クラスの public virtual NSData CreateBookmarkData (NSUrlBookmarkCreationOptions options, string[] resourceValues, NSUrl relativeUrl, out NSError error) メソッドを使います。
  3. セキュリティスコープ ブックマークを解決する - アプリがリソースに再度アクセスする必要がある場合 (再起動後など)、ブックマークをセキュリティスコープ URL に解決する必要があります。 NSUrl クラスの public static NSUrl FromBookmarkData (NSData data, NSUrlBookmarkResolutionOptions options, NSUrl relativeToUrl, out bool isStale, out NSError error) メソッドを使ってブックマークを解決します。
  4. セキュリティスコープ URL からファイルにアクセスすることをシステムに明示的に通知する - この手順は、上記のセキュリティ スコープ URL を取得した直後、またはリソースに対するアクセス権を放棄した後に再びリソースにアクセスする場合に実行する必要があります。 NSUrl クラスの StartAccessingSecurityScopedResource () メソッドを呼び出して、セキュリティスコープ URL へのアクセスを開始します。
  5. セキュリティスコープ URL からファイルへのアクセスを完了したことをシステムに明示的に通知する - アプリがファイルにアクセスする必要がなくなったときは (たとえば、ユーザーがそれを閉じたとき)、できるだけ早くシステムに通知する必要があります。 セキュリティスコープ URL に対するアクセスを停止するには、NSUrl クラスの StopAccessingSecurityScopedResource () メソッドを呼び出します。

リソースに対するアクセスを放棄した後、もう一度手順 4 に戻ってアクセスを再確立する必要があります。 Xamarin.Mac アプリが再起動された場合は、手順 3 に戻ってブックマークを再解決する必要があります。

重要

セキュリティスコープ URL リソースに対するアクセスを解放できない場合、Xamarin.Mac アプリにより、カーネル リソースがリークされます。 その結果、アプリは再起動されるまでファイル システムの場所をコンテナーに追加できなくなります。

アプリ サンドボックスとコード署名

アプリ サンドボックスを有効にし、Xamarin.Mac アプリの特定の要件を (エンタイトルメントを介して) 有効にしたら、サンドボックスを有効にするためにプロジェクトにコード署名する必要があります。 アプリ サンドボックスに必要なエンタイトルメントはアプリの署名にリンクされているため、コード署名を実行する必要があります。

macOS は、アプリのコンテナーとそのコード署名の間にリンクを適用します。これにより、アプリのバンドル ID を偽装している場合でも、他のアプリケーションはそのコンテナーにアクセスできなくなります。 このメカニズムは次のように機能します。

  1. システムはアプリのコンテナーを作成するときに、そのコンテナーに "アクセス制御リスト" (ACL) を設定します。 一覧の最初のアクセス制御エントリには、アプリの "指定要件" (DR) が含まれています。これは、(アップグレードされた場合に) アプリの将来のバージョンをどのように認識できるかについて記述したものです。
  2. 同じバンドル ID を持つアプリが起動するたびに、アプリのコード署名が、コンテナーの ACL に含まれるエントリのいずれかに指定されている指定要件と一致するかどうかがシステムによって確認されます。 一致するものがシステムで検出できなかった場合、アプリは起動できません。

コード署名は次の方法で機能します。

  1. Xamarin.Mac プロジェクトを作成する前に、Apple Developer ポータルから開発証明書、配布証明書、開発者 ID 証明書を取得します。
  2. Mac App Store が Xamarin.Mac アプリを配布する場合は、Apple コード署名で署名されています。

テストとデバッグのときには、署名したバージョンの Xamarin.Mac アプリケーションを使います (これはアプリ コンテナーの作成に使われます)。 後で、Apple App Store からバージョンをテストまたはインストールする場合、そのバージョンは Apple 署名で署名され、起動できません (元のアプリ コンテナーと同じコード署名がないため)。 この状況では、次のようなクラッシュ レポートを受け取ります。

Exception Type:  EXC_BAD_INSTRUCTION (SIGILL)

これを修正するには、Apple 署名バージョンのアプリを指すように ACL エントリを調整する必要があります。

サンドボックス化に必要なプロビジョニング プロファイルの作成とダウンロードの詳細については、前述の「アプリの署名とプロビジョニング」セクションを参照してください。

ACL エントリの調整

Apple 署名バージョンの Xamarin.Mac アプリの実行を許可するには、以下の手順を実行します。

  1. ターミナル アプリ (/Applications/Utilities 内) を開きます。
  2. Finder ウィンドウを開き、Xamarin.Mac アプリの Apple 署名バージョンを表示します。
  3. ターミナル ウィンドウに「asctl container acl add -file」と入力します。
  4. Xamarin.Mac アプリのアイコンを Finder ウィンドウからドラッグし、ターミナル ウィンドウにドロップします。
  5. ファイルの完全なパスがターミナルのコマンドに追加されます。
  6. Enter キーを押してコマンドを実行します。

コンテナーの ACL には、Xamarin.Mac アプリの両方のバージョンに指定されたコード要件が含まれるようになり、macOS でどちらのバージョンでも実行できるようになります。

ACL コード要件の一覧を表示する

以下の手順を実行すると、コンテナーの ACL 内のコード要件の一覧を表示できます。

  1. ターミナル アプリ (/Applications/Utilities 内) を開きます。
  2. asctl container acl list -bundle <container-name>」と入力します。
  3. Enter キーを押してコマンドを実行します。

通常、<container-name> は Xamarin.Mac アプリケーションのバンドル識別子です。

アプリ サンドボックス用の Xamarin.Mac アプリの設計

アプリ サンドボックス用の Xamarin.Mac アプリを設計するときに従うべき一般的なワークフローがあります。 とはいえ、アプリにサンドボックスを実装する詳細は、そのアプリの機能によって異なります。

アプリ サンドボックスを導入するための 6 つの手順

アプリ サンドボックス用の Xamarin.Mac アプリの設計は、通常、以下の手順で構成されます。

  1. アプリがサンドボックスに適しているかどうかを判断します。
  2. 開発と配布の戦略を設計します。
  3. API の非互換性を解決します。
  4. 必要なアプリ サンドボックス エンタイトルメントを Xamarin.Mac プロジェクトに適用します。
  5. XPC を使って特権の分離を追加します。
  6. 移行戦略を実装します。

重要

アプリ バンドル内のメインの実行可能ファイルだけでなく、そのバンドルに含まれるすべてのヘルパー アプリまたはツールもサンドボックス化する必要があります。 これは、Mac App Store から配布されるすべてのアプリに必要です。また、可能であれば、他の形式のアプリ配布でも行う必要があります。

Xamarin.Mac アプリのバンドルに含まれるすべての実行可能バイナリの一覧を表示するには、ターミナルで次のコマンドを入力します。

find -H [Your-App-Bundle].app -print0 | xargs -0 file | grep "Mach-O .*executable"

この [Your-App-Bundle] はアプリケーションのバンドルの名前とパスです。

Xamarin.Mac アプリがサンドボックス化に適しているかどうかを判断する

ほとんどの Xamarin.Mac アプリはアプリ サンドボックスと完全な互換性があるため、サンドボックス化に適しています。 アプリ サンドボックスで許可されていない動作がアプリに必要な場合は、別のアプローチを検討する必要があります。

アプリに次のいずれかの動作が必要である場合、そのアプリはアプリ サンドボックスと互換性がありません。

  • 認可サービス - アプリ サンドボックスでは、「Authorization Services C Reference (認可サービス C リファレンス)」で説明されている関数を使用できません。
  • アクセシビリティ API - スクリーン リーダーなどの支援アプリや、他のアプリケーションを制御するアプリをサンドボックス化することはできません。
  • Apple イベントを任意のアプリに送信する - アプリが未知の任意のアプリに Apple イベントを送信する必要がある場合、サンドボックス化することはできません。 呼び出されるアプリの既知の一覧については、アプリをサンドボックス化することができます。また、エンタイトルメントには呼び出されるアプリの一覧を含める必要があります。
  • 分散通知内のユーザー情報ディクショナリを他のタスクに送信する - アプリ サンドボックスでは、他のタスクにメッセージを送信するために NSDistributedNotificationCenter オブジェクトに投稿するときに、userInfo ディクショナリを含めることはできません。
  • カーネル拡張機能を読み込む - カーネル拡張機能の読み込みはアプリ サンドボックスによって禁止されています。
  • [開く] および [保存] ダイアログでのユーザー入力のシミュレート - [開く] または [保存] ダイアログをプログラムで操作してユーザー入力をシミュレートまたは変更することは、アプリ サンドボックスによって禁止されています。
  • 他のアプリに対するアクセスまたは基本設定の設定 - 他のアプリの設定を操作することは、アプリ サンドボックスによって禁止されています。
  • ネットワーク設定の構成 - ネットワーク設定の操作はアプリ サンドボックスによって禁止されています。
  • 他のアプリの終了 - NSRunningApplication を使って他のアプリを終了することは、アプリ サンドボックスによって禁止されています。

API の非互換性の解決

アプリ サンドボックス用の Xamarin.Mac アプリを設計する場合、一部の macOS API の使用で非互換性が発生する可能性があります。

ここでは、いくつかの一般的な問題と、それらを解決するためにできることを示します。

  • ドキュメントを開く、保存、追跡 - NSDocument 以外のテクノロジを使ってドキュメントを管理している場合は、アプリ サンドボックスのサポートが組み込まれているため、それに切り替える必要があります。 NSDocument は自動的に PowerBox と連携し、ユーザーが Finder でドキュメントを移動した場合にドキュメントをサンドボックス内に保持することをサポートしています。
  • ファイル システム リソースに対するアクセスを維持する - Xamarin.Mac アプリがコンテナーの外部にあるリソースへの永続的なアクセスに依存している場合は、セキュリティスコープ ブックマークを使ってアクセスを維持します。
  • アプリのログイン項目を作成する - アプリ サンドボックスでは、LSSharedFileList を使ってログイン項目を作成することや、LSRegisterURL を使って起動サービスの状態を操作することはできません。 Apple の「Adding Login Items Using the Service Management Framework (サービス管理フレームワークを使ったログイン項目の追加)」ドキュメントの説明に従って SMLoginItemSetEnabled 関数を使います。
  • ユーザー データへのアクセス - getpwuid などの POSIX 関数を使ってディレクトリ サービスからユーザーのホーム ディレクトリを取得している場合は、NSHomeDirectory などの Cocoa または Core Foundation シンボルの使用を検討してください。
  • 他のアプリの設定へのアクセス - アプリ サンドボックスにより、パス検索 API はアプリのコンテナーに誘導されるため、設定の変更はそのコンテナー内で行われ、別のアプリの設定に対するアクセスは許可されません。
  • Web ビューで HTML5 埋め込みビデオを使う - Xamarin.Mac アプリで WebKit を使って埋め込み HTML5 動画を再生する場合は、アプリを AV Foundation フレームワークに対してリンクする必要もあります。 アプリ サンドボックスを使うと、CoreMedia でこのようなビデオを再生できなくなります。

必要なアプリ サンドボックス エンタイトルメントの適用

アプリ サンドボックスで実行する Xamarin.Mac アプリケーションのエンタイトルメントを編集し、[アプリ サンドボックスを有効にする] チェックボックスをオンにする必要があります。

アプリの機能に基づいて、必要に応じて OS の機能またはリソースにアクセスするために他のエンタイトルメントを有効にします。 アプリ サンドボックスは、要求するエンタイトルメントをアプリの実行に必要な最小限に抑えると最も効果的に機能するため、エンタイトルメントはランダムに有効にしてください。

Xamarin.Mac アプリに必要なエンタイトルメントを確認するには、以下の手順を実行します。

  1. アプリ サンドボックスを有効にして、Xamarin.Mac アプリを実行します。
  2. アプリの機能を確認します。
  3. コンソール アプリ (/Applications/Utilities で使用できます) を開き、[すべてのメッセージ] ログで sandboxd 違反を探します。
  4. sandboxd 違反ごとに、他のファイル システムの場所ではなくアプリ コンテナーを使って問題を解決するか、アプリ サンドボックス エンタイトルメントを適用して、制限された OS 機能に対するアクセスを有効にします。
  5. Xamarin.Mac アプリのすべての機能を再実行してテストします。
  6. すべての sandboxd 違反が解決されるまで繰り返します。

XPC を使って特権の分離を追加する

アプリ サンドボックス用の Xamarin.Mac アプリを開発する場合は、特権とアクセスの観点からアプリの動作を確認し、リスクの高い操作を独自の XPC サービスに分離することを検討してください。

詳細については、Apple の「Creating XPC Services (XPC サービスの作成)」とデーモンとサービスのプログラミング ガイドに関する記事を参照してください。

移行戦略を実装する

以前はサンドボックス化されていなかった新しいサンドボックス化されたバージョンの Xamarin.Mac アプリケーションをリリースする場合は、現在のユーザーがスムーズなアップグレード パスを使用できるようにする必要があります。

コンテナー移行マニフェストの実装方法の詳細については、Apple のアプリのサンドボックスへの移行に関するドキュメントを参照してください。

まとめ

この記事では、Xamarin.Mac アプリケーションのサンドボックス化について詳しく説明しました。 まず、アプリ サンドボックスの基本を示すために、単純な Xamarin.Mac アプリを作成しました。 次に、サンドボックス違反を解決する方法を示しました。 次に、アプリ サンドボックスを詳しく確認し、最後に、アプリ サンドボックス用の Xamarin.Mac アプリの設計を検討しました。