🔐

macOS 14 Sonomaで変わったApp Sandboxへの対応

2023/10/14に公開

macOS 14 Sonomaが正式リリースされました。自作のmacOSアプリ macSKK がSonoma対応できているかどうかを確認するためにさっそくアップグレードしてみました。

自作アプリはひとまず問題なく動いたのですが、macOS SonomaでApp Sandbox回りにプライバシー強化の変更があったようで他アプリのApp Containerへのアクセスをユーザーの許可なしにできなくなりました。

https://developer.apple.com/documentation/security/app_sandbox/accessing_files_from_the_macos_app_sandbox

私のアプリには他アプリのApp Containerへアクセスする機能はないのですが、それでもいくつかの変更が必要な箇所がありました。

その1: 署名オプションに Sign to Run Locally を指定したビルドを起動するとアプリ自身のApp Containerにアクセスするときにも確認ダイアログが出る

自作アプリではxcodeprojの Signing & Capabilities の設定では Sign to Run Locally を指定し、リリースビルド時のみ xcodebuildDeveloper ID Application の署名を指定しています。[1]

Sign to Run Locally

これは私のApple Team IDのプロビジョニングプロファイルをもたない人でもビルドやテストがしやすいように設定していました。具体的にはGitHub Actionsで行っているCIやちょっと機能を追加したくなって git clone してみた野良の開発者を想定しています。

macOS 14 Sonomaからの新しいApp Sandbox保護では「Developer ID Application用のProvisioning Profileを使って署名したリリース用アプリ」と「Sign to Run Locally指定のデバッグビルドアプリ」は異なるアプリと認識され、リリース版のmacSKKを使ったことがある状態でデバッグビルドからApp SandboxのData Containerにアクセスしようとすると次のようなダイアログが表示されます。
この状態で 開かない (Don't Open) を選ぶと即座にアプリが終了します。また一度 このまま開く (Open Anyway) を選ぶと同じバイナリの二回目の起動ではこのダイアログは出ないようですが、デバッグビルドを更新すると再び表示されます。

日本語環境 英語環境

調べたところ、developer.apple.comのApp Sandboxに次のような文章がありました。

In macOS 14 and later, the operating system uses your app’s code signature to associate it with its sandbox container. If your app tries to access the sandbox container owned by another app, the system asks the person using your app whether to grant access. If the person denies access and your app is already running, then it can’t read or write the files in the other app’s sandbox container. If the person denies access while your app is launching and trying to enter the other app’s sandbox container, your app fails to launch.
https://developer.apple.com/documentation/security/app_sandbox/accessing_files_from_the_macos_app_sandbox#4144038

DeepL:

macOS 14以降では、オペレーティングシステムはあなたのアプリのコード署名を使用して、そのアプリをサンドボックスコンテナに関連付けます。あなたのアプリが他のアプリが所有するサンドボックスコンテナにアクセスしようとすると、システムはあなたのアプリを使用している人にアクセスを許可するかどうかを尋ねます。その人がアクセスを拒否し、あなたのアプリがすでに実行されている場合、他のアプリのサンドボックスコンテナ内のファイルを読み書きすることはできません。あなたのアプリが起動し、他のアプリのサンドボックスコンテナに入ろうとしているときに、その人がアクセスを拒否した場合、あなたのアプリは起動に失敗します。

このダイアログは一度「このまま開く」を選んでもビルドが更新される度に現れるため開発中のユニットテストでは非常にストレスです。(動作確認時はあきらめて毎回Open Anywayする)
ユニットテストの実行時にApp SandboxのData Containerのファイルアクセスをしないように分岐を書くことでこのダイアログは出なくなりました。[2]

… と思ってたんですが、どうも修正が完全ではなかったのか、まだこのダイアログが出てしまうようです。

In certain situations, two different versions of your app can have different designated requirements, leading the operating system to request permission when the second version tries to access the sandbox container. One case is using both the version of your app from the Mac App Store and a local build created in Xcode on the same computer. Another is if you transfer an app to another App Store team and the code signing identity used to sign the app changes between released versions.

DeepL:

特定の状況では、あなたのアプリの2つの異なるバージョンは、異なる指定要件を持つことができ、2番目のバージョンがサンドボックスコンテナにアクセスしようとしたときに、オペレーティングシステムが許可を要求することにつながります。1つのケースは、Mac App Store からのアプリのバージョンと、同じコンピュータ上の Xcode で作成されたローカルビルドの両方を使用することです。もう 1 つは、あなたが別の App Store チームにアプリを転送し、アプリに署名するために使用されるコード署名 ID が、リリースされたバージョン間で変更された場合です。

「Mac App Store からのアプリのバージョンと、同じコンピュータ上の Xcode で作成されたローカルビルドの両方を使用することです」
いやいやいや開発してればそういうことってめちゃくちゃあると思うんですよ。

GitHub Actionsの環境がmacOS 14になったら正しいApple Development Programの証明書をGitHub Actions環境で使えるようにセットアップしないといけなくなりそうでめんどくさいですね、嫌だなあ…

macOS 14+ でしか動かないXcodeが出る前になにかしらのローカル/CIでの開発のノウハウが集まることを期待しています。うーん辛い。

その2: デバッグビルドを起動すると「"(アプリ名)"がほかのアプリからのデータへのアクセスを求めています。」というダイアログが出る

これもmacOS SonomaのApp Sandbox Data Container保護によるものです。
デバッグビルドのmacSKKが、リリースビルド用であるSandbox Data Containerにあるファイルへアクセスしようとするとこのダイアログが出るようです。

このダイアログは一度許可すれば二度と許可を求められることはないようです。System SettingsPrivacy & Security を見てみましたがアクセスを許可したアプリ一覧のような画面はなさそうでした。

自己責任でデバッグビルドを使うときには許可すればよいので、例えばOSSの場合は「開発者向けの注意」として「Team IDが異なるProvisioning Profileで署名したビルドを使うとこういうダイアログが出るよ」といった注意をREADMEに書いておくとよいかもしれません。

また、macOS 14からInfo.plistに NSAppDataUsageDescription というキーで「他のアプリのApp Containerへアクセスする理由」を記述ができるようになったので、ほんとうに他アプリのApp Containerへアクセスをする可能性のアプリの開発時には設定したほうがよいでしょう。
https://developer.apple.com/documentation/bundleresources/information_property_list/nsappdatausagedescription

その3: インストーラーがApp Sandbox Data Containerに書き込むときに確認ダイアログが表示される

私が配布しているアプリケーションはインストール時にApp SandboxのData ContainerにSKK用の辞書ファイルを書き込むようにしています。つまりインストール時に ~/Library/Containers/net.mtgto.inputmethod.macSKK/Data/Documents/Dictionaries にファイルを作成しています。

ところがmacOS 14 Sonomaから、App SandboxのData Containerにファイルを書き込もうとするときにダイアログが表示されるようになりました。

"Installer" would like to access data from other apps.

Don't Allow を選ぶとインストールが中断されてしまいます。
Allow を選ぶとインストールはできますが、次回インストール時も同じダイアログが表示されてしまいます。

pkgファイルは正規の Developer ID Installer 証明書で署名している (productsignコマンド) のですがそれだけではだめのようです。

自分の想像では、インストーラアプリ (Bundle Identifier: com.apple.installer) がほかのアプリ (= 私の作成したアプリ) のApp Sandbox Data Containerにかきこもうとしてユーザーに許可を求めてるんじゃないかなと思うのですが、もしそうだとするとこのダイアログを防ぐことは難しそうです。

自力ではわからなかったので、ひとまず Apple Develop Forumsに質問を投げてみました 。なにか反応があれば追記します。

2023-10-22追記

上記フォーラムでAppleのスタッフから返信をいただきました。助言に従い完全に新規の環境でインストールしてみたところインストーラによるダイアログ表示は再現しませんでした。さらにインストール後に一回アプリを起動したあとにアップデートインストールしても再現しませんでした。

もしかすると その1 で adhoc署名ビルドを使っていたためApp Sandbox Data Containerの持ち主が不在になっていたのかもしれません。少なくとも私の環境ではローカルでの開発時にもリリースと同じTeam IDの証明書を使うことでダイアログによる警告は出なくなりました。

まとめ

macOS 14 SonomaではApp Sandboxにセキュリティ強化が入り、他アプリのApp Container (App Sandbox Data Container) へのアクセスに制限がかかるようになりました。

同じアプリであっても別のTeam IDをもつ証明書やadhoc署名 ( Sign to Run Locally ) のアプリからApp Containerへファイルアクセスしようとするとダイアログでユーザーに許可を要求するようになりました。pkgファイルから起動するインストーラも同様に自分のアプリのApp Containerへのアクセス権限を持たないようです。

アクセスが必要なアプリを作成する場合はユーザーに適切に許可が必要な説明を行うようにするのがよいでしょう。

参考: 私の環境でのリリースビルドとデバッグビルドの署名の違い

Developer ID ApplicationであるProvisioning Profileを使っているリリース版ビルド

Authorityに正規の"Developer ID Application"が使われていることや、TeamIdentifier (Team ID) を確認できます。
"Developer ID Application" を使っているのは私のアプリは Mac App Store 配布できない形式なので、notarytool を使って独自でAppleの公称を受けるためです。

❯ codesign -dvv -r - ~/Library/Input\ Methods/macSKK.app
Executable=/Users/(ユーザー名)/Library/Input Methods/macSKK.app/Contents/MacOS/macSKK
Identifier=net.mtgto.inputmethod.macSKK
Format=app bundle with Mach-O universal (x86_64 arm64)
CodeDirectory v=20500 size=5128 flags=0x10000(runtime) hashes=149+7 location=embedded
Signature size=9046
Authority=Developer ID Application: Satoshi Gotou (W3A6B7FDC7)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=Oct 8, 2023 at 10:11:39
Info.plist entries=34
TeamIdentifier=W3A6B7FDC7
Runtime Version=14.0.0
Sealed Resources version=2 rules=13 files=7
designated => anchor apple generic and identifier "net.mtgto.inputmethod.macSKK" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = W3A6B7FDC7)

Sign to Run Locallyを指定して署名したビルド

Signature=adhocとなっており、またAuthorityTeamIdentifier (Team ID) が設定されていません。

❯ codesign -dvv -r - /path/to/debug/build/macSKK.app
Executable=(省略)
Identifier=net.mtgto.inputmethod.macSKK
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20400 size=19349 flags=0x2(adhoc) hashes=594+7 location=embedded
Signature=adhoc
Info.plist entries=33
TeamIdentifier=not set
Sealed Resources version=2 rules=13 files=17
# designated => cdhash H"874bc319b57ff9210a2f2220199419a5c06a0903"

インストーラ

Develoer ID Installer 証明書で署名しています。

❯ pkgutil --check-signature /Volumes/macSKK/macSKK-0.9.1.pkg
Package "macSKK-0.9.1.pkg":
   Status: signed by a developer certificate issued by Apple for distribution
   Notarization: trusted by the Apple notary service
   Signed with a trusted timestamp on: 2023-10-08 01:11:41 +0000
   Certificate Chain:
    1. Developer ID Installer: Satoshi Gotou (W3A6B7FDC7)
       Expires: 2027-02-01 22:12:15 +0000
       SHA256 Fingerprint:
           4B 04 F9 16 DA 30 68 EC 00 BC 5B B5 F6 E2 C4 88 FC 22 A3 F7 F3 1B
           A1 A5 06 B7 54 27 01 0B 37 12
       ------------------------------------------------------------------------
    2. Developer ID Certification Authority
       Expires: 2027-02-01 22:12:15 +0000
       SHA256 Fingerprint:
           7A FC 9D 01 A6 2F 03 A2 DE 96 37 93 6D 4A FE 68 09 0D 2D E1 8D 03
           F2 9C 88 CF B0 B1 BA 63 58 7F
       ------------------------------------------------------------------------
    3. Apple Root CA
       Expires: 2035-02-09 21:40:36 +0000
       SHA256 Fingerprint:
           B0 B1 73 0E CB C7 FF 45 05 14 2C 49 F1 29 5E 6E DA 6B CA ED 7E 2C
           68 C5 BE 91 B5 A1 10 01 F0 24

productsign で署名し、notarytool で公称を通しています。

❯ xcrun stapler validate /Volumes/macSKK/macSKK-0.9.1.pkg
Processing: /Volumes/macSKK/macSKK-0.9.1.pkg
The validate action worked!

参考リンク

https://developer.apple.com/documentation/security/app_sandbox/accessing_files_from_the_macos_app_sandbox
https://lapcatsoftware.com/articles/2023/6/1.html
https://developer.apple.com/videos/play/wwdc2023/10053/
https://developer.apple.com/documentation/technotes/tn3127-inside-code-signing-requirements

脚注
  1. リリースビルドを作成するときはMac App Store以外で配布するため Developer ID Application で署名します。xcodebuildの引数で CODE_SIGN_IDENTITY="Developer ID Application" DEVELOPMENT_TEAM=$(APPLE_TEAM_ID) のように指定することで署名することができます。 ↩︎

  2. ベストプラクティスかは知りませんが Edit Scheme でTestの実行時にだけ環境変数 MACSKK_IS_TEST をセットして実行時に分岐しています。 ↩︎

Discussion