Search Unity

Unity アプリで URL ハンドラーと OpenURL を安全に使用する方法

, 11月 6, 2019

Unity Security チームは、Unity のクリエイターがより信頼できるゲームやアプリケーションを構築できるようサポートすることに注力しています。このブログシリーズでは、Unity でより安全なゲームやアプリを制作するためのヒント、テクニック、推奨事項を紹介します。

本日公開したこの記事を皮切りに、今後 Unity を使った安全な開発に関するブログシリーズを展開していきます。このシリーズでは、Unity の開発者が制作中のゲームやアプリケーションに直接適用できるコンテンツを提供します。Unity の製品やサービスを使用するうえでのベストプラクティスにフォーカスし、基本的な知識から高度なノウハウに至るまで、幅広いトピックを網羅できればと考えています。取り上げてほしいテーマがある場合は、私たちにお知らせください。皆さんのご意見、ご感想をお待ちしております。このブログでは、主に URL ハンドラーの概要について取り上げます。

Unity アプリで URL ハンドラーと OpenURL を安全に使用する方法

URL ハンドラーやファイルハンドラーは、ファイルタイプをその特定のファイルを開くことのできるインストール済みのプログラムと関連付けますが、それにはリスクが伴います。たとえば、ローカルマシンで作業しているときに、ローカルドライブからある PDF ファイルをダブルクリックして開くと、オペレーティングシステムはファイルハンドラーの一覧を参照してそのファイルタイプに割り当てられているプログラムを選択します。これにより、PDF ファイルはそのファイルを正しく開くことのできるプログラムで開かれます。ファイルハンドラーは、一般的にファイル拡張子(.pdf など、ファイル名の最後に付くサフィックス)からファイルの処理方法を判断します。

同様のメカニズムが URL ハンドラーでも使用され、パスのプレフィックスに基づいて URL を開く方法を判断します。例としては、おなじみの http:// プロトコルが挙げられるでしょう。これによってデフォルトのブラウザーが開かれます。一般的な URL スキームのもう 1 つの例として、file://c:/windows/system32/drivers/gmreadme.txt が挙げられます。この URL を実行すると、Windows でこのライセンスファイルがメモ帳で開かれます。

URL ハンドラーはお使いのオペレーティングシステムで使用できる便利な機能で、アプリケーションを起動するときの時間の節約につながります。ただし、この便利なメカニズムは安全でないことがあります。

なぜ Unity のゲームで URL ハンドラーが問題になるのか?

Unity エディターと Unity ランタイムは両方とも、.NET Framework を使用すること以外に、Application.OpenURL と呼ばれる Unity のスクリプティング API を通じて、URL ハンドラーのプログラマティックな使用をサポートしています。ゲーム開発者は、プレイヤーがゲーム内のリンクをクリックするとローカルシステムの Web ブラウザーが起動するよう設定するために、OpenURL を使用することがよくあります。ただし、ゲーム開発者が Application.OpenURL に渡される情報を適切にサニタイズしていない場合、プレイヤーを危険にさらすことになりかねません。

このスクリプティング API は本質的には危険なものではありませんが、渡される URL の一部に信頼されていない入力が使用されているケースでは、注意を要します。

注意:信頼されていない入力

信頼されていない入力/データとは、信頼されているソースから提供されたものでないあらゆるデータのことです。そもそも信頼されているソースとは何でしょうか?この記事のコンテキストにおいては、厳密な HTTPS が有効になっているエンドポイントのみが信頼されていると考えてください。

信頼されていない入力の例は多数あります。チート防止システムを設計している場合は、プレイヤーのローカルファイルシステムは信頼されていないものと見なされます。マルチプレイヤーゲームを開発している場合は、すべてのプレイヤーは信頼されていないものと見なされます。

データや入力を保護する方法としては、公開鍵と秘密鍵を使用した暗号化などを活用する方法が挙げられますが、この記事では取り上げません(この詳細について興味をお持ちの方は、コメントを残してください)。

不正な URL の処理と安全でない使用方法

これらのハンドラーはユーザーにとって非常に利便性が高いものですが、リスクもはらんでいます。Application.OpenURL の安全でない使用方法の例を紹介します。

図 1. Application.OpenURL の安全でない使用方法の例

この例では、ゲーム内コメントシステムでユーザーにリンクを共有することを許可しています。ユーザーがリンクをクリックすると、VulnerableBrowserClass.OpenBrowser 関数が呼び出されます。

図 2. 危険をはらんでいる可能性があるリンクのサンプルシナリオ

このように、危険に気付いていないユーザーに対して、危険をはらんでいる可能性のあるアプリケーションへのリンクを簡単に送信できることがわかります(図 2)。図 1 に示すように、その URL が Application.OpenURL に直接渡されると、被害を受けたマシンは即座にそのリンク先のアプリケーションを実行し、攻撃者にそのマシンの制御を奪われてしまう可能性があります。

上の図では、攻撃者が上記のリンクの形式を変更して、チャットウィンドウに https://SuperLeetCheats.com/VulnTheGame として表示しつつも、実際のリンクは file://leethaxorz.net/super_malware.exe でマルウェアのある場所に誘導しています。ここでの問題は、ユーザーが互いにリンクを送信できることではなく、上記のコードサンプル(図 1)に示すように、(攻撃者である可能性がある)ユーザーによって送信されたリンクが、一切の検証もサニタイズもなしに、Application.OpenURL に直接渡されることです。サニタイズなしでは、上記のリンクがクリックされると、ファイルが Unity エディターでターゲットプレイヤーの OS に直接渡され、結果として攻撃者のマルウェアが実行されてしまいます。

そのリスクに対処するにはどうすればいいですか?

Application.OpenURL を使用する最も安全な方法は、信頼されていないデータと一緒には絶対に使用しないことです。開発者またはサーバーから提供された URL を開く目的だけのために、かつ信頼された転送(HTTPS)経由でのみ使用してください。

リモート設定を使用する(例:新しい更新プログラムのためにコンテンツ URL のリストをホストする)場合は、厳格な適用により、HTTPS 経由で取得したデータであることを確認します。必ずこの方法でリモートコンテンツを取得してください。

注意:HTTPS では、上記の攻撃で説明されている、信頼されていない/サニタイズされてない入力によるアプリ内の脆弱性は修正されません。一方、プレイヤーに送信されるデータが転送中に改ざんされていないことが保証されます。

信頼されていないソースからのデータで OpenURL を使用することが絶対に必要であると判断した場合は、信頼されていないソースから受け取った入力をサニタイズするために最善を尽くさなければなりません。これを行う方法はいくつかあります。たとえば、正規表現によるパターンマッチングを使用する方法、.NET ライブラリを介して URL を構築する方法、外部のサニタイゼーションライブラリを活用する方法などです。ただし、これらの対策は 100% 効果があるとは限らず、どのソリューションを選択しても、信頼されていないデータで Application.OpenUrl(および同様の機能)が使用される場合は、潜在的なリスクが想定されます。

さらに、図 2 で示しているように、ユーザーにリンクの背後にある URL を知るすべはありません。最低でも、アクセスする URL 全体をユーザーに対してプロンプトで表示してください。ただし、ユーザーは目の前にどのようなプロンプトが表示されても熟考せずにクリックしがちなので、これが確実な解決策であるとは考えないでください。

なぜ OpenURL やファイルハンドラーが問題になるのでしょうか?

OpenURL やファイルハンドラーを使用するのは開発者にとってごく一般的なことです。特に、ユーザーがゲーム外のインターネット上に存在するコンテンツを共有することが多い、リッチメディアアプリケーションやソーシャルメディアのような機能 (ゲーム内チャット、レビュー、コメントなど) と共に使用されます。さらに、生産性を高める一般的なシナリオで使用されます。たとえば、設定ファイルを編集するときは、リンクを OS に渡してユーザーが使用しているコード編集アプリケーションを開くようにするほうが、ユーザーにとって便利です。Application.OpenURL は、ファイルハンドラーをサポートする、プラットフォームに依存しない API です。これを使用することで、Unity の開発者はプラットフォームごとに別個のハンドラーを作成する必要がなくなります。

これは Unity エディターやランタイム独自のものですか?

いいえ。ここまでで説明したように、これはほとんどのオペレーティングシステムで使用されている一般的な機能で、数多くの言語やフレームワークでサポートされています。Windows API である Windows.System.LauchURIAsync(ユニバーサル Windows プラットフォーム [UWP] アプリ用)や悪名高い System.Diagnostics.Process.Start の使用については注意を払うようにしてください。これらのネイティブな .NET ライブラリは、両方とも Application.OpenURL と同じ機能を提供します。LaunchURIAsync は Windows のセキュアなアプリケーションサンドボックス内からアプリケーションを起動することを許可し、Process.Start はローカルシステムであらゆる実行ファイルを起動するために使用できます。さらに、一部の OS のネイティブな呼び出しが同じ機能を提供します(Apple の open(_:options:completionHandler:) など)。このような種類の API はすべて、信頼されていない入力やサニタイズされていない入力が API に渡された場合は簡単に悪用されてしまいます。

今後の予定

Unity では、Unity を使用した開発において、安全性に関わるベストプラクティスを実践し、維持するために必要不可欠なトピックを取り上げたブログ記事を定期的に公開する予定です。今後のトピックとして、ゲームデータの安全な転送や、安全なソフトウェア開発のためのライフサイクル(SSDLC)の民主化などを取り上げます。また、社内用のガイダンスやセキュリティツールの一部をオープンソース化することにも取り組んでいます。

今後の記事で取り上げてほしい安全性に関するトピックについてご意見、ご要望がありましたら、Unity までお知らせください。

セキュリティに関わるアドバイスなどの詳細については、Unity Security のページをご覧ください。

4 replies on “Unity アプリで URL ハンドラーと OpenURL を安全に使用する方法”

It would be great to know more about protecting data inside unity application. How to prevent extraction of models, scripts and configuration files especially for offline installations? How to license unity application to prevent starting on unregistered machine and controlling application distribution? How to create protected communication between Unity application and Operational System Services and Applications. I actually have a lot of security questions and would love to share it:)

I can’t speak directly to preventing extraction of assets, or how licensing in the Editor works, but I do think communication between Unity apps and other services would be a great topic we can cover. We’ll keep this in mind for future blog posts; I think this is a great topic to share with the community.
Thanks for the feedback Kirill! 👍

Yes, it will be great topic! I just want to clarify. When I said about licensing and preventing extraction I meant extraction of assets, scripts from Unity build and licensing for Unity build. It can be techniques like obfuscation, encryption, authorization, device installation control, etc. When working with B2B segment it is frequent case to protect application and user data.

Quick reminder that System.Diagnostics.Process support for il2cpp would be highly appreciated. We run external plugins using our native C code but would also like to read it’s output, control how it behaves etc but currently we can’t dedicate time making it in C/C++.

Comments are closed.