OSX10.9におけるGUIスクリプティングとセキュリティとの戦い

AppleScriptにはGUIスクリプティングという最後の切り札がある。GUIスクリプティングは、OSが認識するGUIオブジェクトを直接指定して操作する方法である。AppleScriptに対応していないアプリケーションであっても、GUIスクリプティングを使えば、ある程度自由に操作できる。かなり便利で、よく使っていた。

GUIオブジェクトとは、画面に表示されるウィンドウとか、ボタンとか、テキスト等の、OSが管理しているあらゆる表示物である。そのようなものを自由に操作できるようになると、場合によっては悪意のある操作を実行することも可能になる。そのためセキュリティ上の危険性を考慮してか、Appleは長らく、たった1つの制約を付けていた。

GUIスクリプティングを実行するには、システム環境設定 >> アクセシビリティ >>「補助装置にアクセスできるようにする」をオン(チェックあり)にしておく必要があった。(OSX 10.8まで)

OSデフォルトはオフなのだけど、自分は当然、常にオンである。オフにすることなんて考えられない。例えれば、今時のWebブラウザで「JavaScriptを有効にする」が常にオンであり続けるのと同じ感覚である。GUIスクリプティングが使えなくなると、多くの場面で不便が生じる。だから、チェックを入れるひと手間はあるが、チェックさえ入れてしまえば常にGUIスクリプティングが実行可能になるOSX10.8までの状況は、自分にとっては素晴らしい環境であった。

一方、OSX10.9では、GUIスクリプティングに対するセキュリティ管理の方法がまったく別物になってしまった。かつての「補助装置にアクセスできるようにする」設定は消え去り、システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティとして生まれ変わった。新たな設定方法では、GUIスクリプティングを許可するアプリケーションを個別に登録する必要がある。

アプリケーションごとに許可する・しないを設定する必要があるので、確かに安全性は向上するのだけど、必要なアプリケーションが許可されていない初期状態では、GUIスクリプティングが思いどおりに実行されず、不便な思いをすること必至。また、最初はその仕組みもよく分からず、イライラを募らせていた。何をどう設定すれば、以前の利便性を取り戻せるのか、GUIスクリプティングを制限するセキュリティとの戦いの記録を残しておこうと思う。

必要なアプリケーションを許可する

AppleScript エディタ.appを許可する


tell application "System Events"
tell process "AppleScript Editor"
set frontmost to true
click menu bar 1's menu bar item "ファイル"
click menu bar 1's menu bar item "ファイル"'s menu 1's menu item "最近使った項目を開く"
end tell
end tell

  • そして実行してみると、以下のようなエラーが表示される。

  • OKボタンを押して、システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティ を確認してみると...

  • その項目に「AppleScript エディタ.app」が追加されている。

  • その後もう一度AppleScript エディタから実行してみると、

今度はちゃんと実行できた!(ファイル >> 最近使った項目を開く メニュー操作が実行された)

SystemUIServer.appを許可する

  • ところが実行しても、何も起こらない...。
  • すかさず、システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティ を確認してみると、SystemUIServer.appが追加されている。

今度はちゃんと実行できた!(ファイル >> 最近使った項目を開く メニュー操作が実行された)

  • つまり、スクリプトメニューからAppleScriptを実行する場合は、SystemUIServer.appを許可しておく必要があるのだ。
  • 同じgui_scripting.scptをAppleScript エディタで開いて実行する場合は、AppleScript エディタ.appを許可しておく。


このように、AppleScriptを実行する環境をそれぞれ個別に許可しておく必要があるのだ。
これが、OSX10.9からのGUIスクリプティングのセキュリティ管理の仕組みの基本である。

Quicksilver.appを許可する
  • となると、gui_scripting.scptをQuicksilverから起動してみると、やはり何も起こらない...。
  • すかさず、システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティ を確認してみると、Quicksilver.appが追加されている。

今度はちゃんと実行できた!(ファイル >> 最近使った項目を開く メニュー操作が実行された)

ターミナル.appを許可する
  • ターミナルを開いて、osascriptコマンドを使って実行してみた。
  • 「補助アクセスは許可されません。 (-1719)」というエラー発生。
$ osascript /Users/zari/Library/Scripts/gui_scripting.scpt
/Users/zari/Library/Scripts/gui_scripting.scpt: execution error: System Events got an error: osascript には補助アクセスは許可されません。 (-1719)
  • すかさず、システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティ を確認してみると、ターミナル.appが追加されている。

今度はちゃんと実行できた!(ファイル >> 最近使った項目を開く メニュー操作が実行された)

caffeinateコマンドを許可する
  • 自作のtimerコマンドを使って、定期的な繰り返し処理を実行している。
  • timerコマンドは、launchdとpmset scheduleを利用している。
  • そして、launchdから実行する時は、処理中に無用なスリープをしないように、caffainateコマンドでラップして実行している。
    • 例えば「caffeinate osascript $HOME/Library/Scripts/gui_scripting.scpt」を実行している。
  • そのような場合、caffeinateコマンドにもGUIスクリプティングを許可しておく必要があるようだ。
BetterTouchTool.appを許可する
  • 以上のように試行錯誤を繰り返していると、いつの間にかBetterTouchTool.appも追加されていた。

  • BetterTouchTool.appは、マルチタッチジェスチャーを高度にカスタマイズできる、必携のアプリである。
  • BetterTouchTool.appも、その内部でGUIスクリプティングを利用しているらしく、許可しておく必要があるようだ。

アプレットとの戦い

アプレットを許可する
  • アプレットとは、ファイルフォーマット=アプリケーションとして保存したAppleScriptのことである。
    • 一般的なアプリケーションと同じように振る舞う。
  • 例えば、gui_scripting.scptをファイルフォーマット=アプリケーションに変更して、保存してみる。(gui_scripting.app)
  • すると、AppleScript エディタから実行する時は、以前と変わらず実行できるが、
  • gui_scripting.appのアイコンをダブルクリックして実行すると、エラーが表示された。
    • スクリプトメニューから実行しても、エラーが表示された。
    • Quicksilverから実行しても、エラーが表示された。

←OKを押した。
←システム環境設定を開くを押した。

  • システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティ を確認してみると、gui_scripting.appが追加されている。

  • チェックありにして、GUIスクリプティングを許可しておく。
  • その後、もう一度アイコンをダブルクリックしてみると...

今度はちゃんと実行できた!(ファイル >> 最近使った項目を開く メニュー操作が実行された)

アプレットを修正した場合
  • では、先ほどのアプレットを修正してみる。(実験なので、コメントを追加しただけの意味のない修正)


--何らかの修正
tell application "System Events"
tell process "AppleScript Editor"
set frontmost to true
click menu bar 1's menu bar item "ファイル"
click menu bar 1's menu bar item "ファイル"'s menu 1's menu item "最近使った項目を開く"
end tell
end tell

  • その後実行すると、再び「補助アクセスは許可されません」のエラーメッセージが表示されてしまう...。

  • 一旦、システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティ >> gui_scripting.appのチェックを外し、
  • 再び、チェックを入りにすることで、gui_scripting.appのGUIスクリプティングが正常に実行できるようになった。
  • どうやらアプレットが修正された場合、その都度、許可設定をやり直す必要があるようだ。

OSX10.9では、アプレットやアプリケーションの変化まで監視しているのだ!

  • この仕組みによって安全性は高まるのかもしれないが、頻繁に修正しながらアプレットの完成度を高めようとすると、激しく不便を感じる。

プロパティとの戦い

  • 変化を監視しているならば、プロパティを持つアプレットの扱いはどうなるのだろうか?という疑問が湧いてくる。
  • AppleScriptでは、処理中に変化したプロパティの値を、実行終了後も永続的に保持する。
  • 永続的に保持するためには、通常、ファイルとして保存しておく必要がある。
  • それではプロパティは一体どこに保存されているのか?
  • 実は、アプレットスクリプトのファイル本体に含めて保存されているのだ。

プロパティが変化すると、アプレットスクリプトのファイル変更日も更新されるのだ!

  • かつて、この荒技(自己修正)とも言える仕組みを知った時、驚愕した...。

つまり、プロパティが変化するとは、アプレットが修正されるのと同じことなのである。

Appleの回答
  • この疑問に対するAppleの回答は、以下のようになっている。

デフォルトでは、OS X Mavericksアクセシビリティ機能を使用するアプレットは、実行するときにプロパティを保存しません。プロパティを保存するアプレットは、その情報を保存するためにアプレット自体のコンテンツを修正します。この自己修正のために、アプレットが実行されるたびに異なるアプリケーションとして OS X に表示されます。このために認証プロセスが何度もトリガされます。

OS X:Mavericks でアクセシビリティとセキュリティ機能を使った AppleScript の使用方法 - Apple サポート
  • 相変わらず、Appleの文書は分かりにくい...。
    • アクセシビリティ機能を使用するアプレットは、実行するときにプロパティを保存しません」と言っているのに、
    • 「自己修正のために、アプレットが実行されるたびに異なるアプリケーションとして OS X に表示されます。」とも言っている。
  • プロパティを保存しないなら、自己修正されないはずなのに、一体どうゆうこと?
プロパティを持つアプレットの実験
  • こうゆう時は、実際に試してみるのが手っ取り早い。
  • 以下のようなプロパティ付きのアプレットにしてみた。


property counter : 0
set counter to counter + 1
display notification counter

delay 1

tell application "System Events"
tell process "AppleScript Editor"
set frontmost to true
click menu bar 1's menu bar item "ファイル"
click menu bar 1's menu bar item "ファイル"'s menu 1's menu item "最近使った項目を開く"
end tell
end tell

  • アプレットをダブルクリックで実行すると、コードが修正されたのだから、当然実行できない。
    • 変数counterの値=1、「補助アクセスは許可されません」のエラーメッセージ。
  • もう一度ダブルクリックで実行してみても、やはり実行できない。
    • 変数counterの値=2、「補助アクセスは許可されません」のエラーメッセージ。
  • ここで、システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティgui_scripting.appの許可設定を、切・入して再設定してみる。
  • その後にダブルクリックで実行してみると、今度は実行できた!
  • その後は、何度でも正常に実行できる。
  • 以上の結果から、以下のように理解した。

GUIスクリプティングが許可されていないアプレットは、プロパティを保存する。
一方、GUIスクリプティングが許可されるアプレットは、プロパティを保存しない。

Appleの抜け道の解説
  • 以上の仕組みでは、プロパティを保存しながらGUIスクリプティングを実行するアプレットは作れないことになってしまう。
  • また、コードを修正する度に、許可を再度設定するのも面倒である。
  • それらを回避する方法として、Appleは以下の方法を解説している。
  • ところが、自分の環境では何度試しても、うまく設定できない...。
    • OSX10.9.1
    • AppleScript2.3

アクセシビリティと永続的なプロパティ値の両方が必要なアプレットがある場合は、以下の手順を行って、再許可がなくても動作できるようにサインインします。


重要:以下の手順を使ってアプレットにサインインすると、不正なソフトウェアがユーザの許可なくアクセシビリティを使用するというセキュリティの脆弱性を招くことがあります。


関連するプロパティリストファイルをダウンロードしてインストールする

  1. この特別なプロパティリストファイル (plist) へのリンクを「option」キーを押しながらクリック、右クリック、または「control」キーを押しながらクリックします。
    ResourceRules-ignoring-Scripts.plist
  2. 表示されるショートカットメニューから、リンク先のファイルをダウンロードするオプションを選択します。
  3. ダウンロードしたプロパティリストファイルを「/ライブラリ/Preferences」フォルダに入れます。
    ヒント:「ライブラリ」フォルダにアクセスするには、キーボードの「option」キーを押しながら Finder で「移動」>「ライブラリ」と選択します。


ターミナルを使って plist ファイルをアクティベートする

  1. ターミナルを起動します。
  2. 次のコマンドを使います。プロパティリストファイルとターゲットの AppleScript アプレットの両方のパスを、実際の正しいパスにします。
codesign -s - --resource-rules=/Users/YourUserNameHere/ResourceRules-ignoring-Scripts.plist /path/to/applet.app

注意:署名 ID がある場合は、-s オプションに「-」の代わりに自分の署名 ID を使うことができます。

OS X:Mavericks でアクセシビリティとセキュリティ機能を使った AppleScript の使用方法 - Apple サポート
プロパティを保存しながらGUIスクリプティングを実行可能なアプレットの作り方

結局、自分は以下の方法に辿り着いた。

  • アプレットの「バンドルの内容」を表示して、識別子をコピーする。

  • ターミナルで、以下のコマンドを実行した。
#設定
$ codesign -s - -i com.apple.ScriptEditor.id.gui-test -f $HOME/Library/Scripts/gui_scripting.app

#確認
$ codesign -dv $HOME/Library/Scripts/gui_scripting.app
Executable=/Users/zari/Library/Scripts/gui_scripting.app/Contents/MacOS/applet
Identifier=com.apple.ScriptEditor.id.gui-test
Format=bundle with Mach-O universal (i386 x86_64)
CodeDirectory v=20100 size=203 flags=0x2(adhoc) hashes=3+3 location=embedded
Signature=adhoc
Info.plist entries=13
Sealed Resources version=2 rules=12 files=4
Internal requirements count=0 size=12
  • システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティgui_scripting.appの許可設定を、切・入して再設定する。

  • 切・入のタイミングによってはうまく再設定できないことがあるので、その場合は何度かこの手順を繰り返すと再設定できた。


その後、アプレットをダブルクリックで実行すると、プロパティを保存しつつ、GUIスクリプティングのメニュー操作も実行された!

システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティのクリア

  • 実験しているうちに、アクセシビリティに無用なアプレットやアプリケーションが追加されてしまった...。
  • そんな時は、tccutil reset Accessibilityコマンドによって、許可項目をすべてクリアできる。
$ tccutil reset Accessibility

注意:上記のコマンドを実行すると、アクセシビリティの許可設定はすべてクリアされてしまう。

システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティに素早く追加する

  • 上記で一旦クリアしてしまった項目を、再びアプリケーションやアプレットスクリプトを実行しながら追加するのは非常に面倒である。
  • 実は、システム環境設定 >> セキュリティとプライバシー >> プライバシー >> アクセシビリティへは、ドラッグ&ドロップ可能である。
  • システム環境設定 左下の鍵のロックを解除して、アプリケーションのアイコンをドラッグすれば、チェックありの状態で追加できる。

キー操作はGUIスクリプティングとして制限されない

  • 以前からそうなっていたように、キーボードの操作についてはGUIスクリプティングの許可は不要である。
  • 例えば、以下のようなアプレットを作成して、ダブルクリックで実行すると、許可なしで正常に実行される。


tell application "System Events"
tell process "AppleScript Editor"
set frontmost to true
keystroke "L" using {command down, shift down} end tell
end tell