LASSIC Media らしくメディア
アプリの画面キャプチャ防止の実装
LASSIC IT事業部|元請(プライムベンダー)としてシステム保守・運用を受託
この記事のポイント
- モバイルアプリの画面キャプチャ防止は、スクリーンショット・画面録画・画面共有(ミラーリング)という3種の経路を区別して対策を設計する必要があります。
- AndroidはFLAG_SECUREでOS標準の抑止が可能ですが、iOSにはスクリーンショットを技術的に止める公開APIが無く、検知して隠す設計が中心になります。
- 実装は端末OSのバージョン差や既存機能への影響を考慮する必要があり、外注と内製の判断軸を整理してから着手することが有効です。
目次
画面キャプチャ防止とは何を指すか
モバイルアプリの画面キャプチャ防止とは、機密性の高い画面がスクリーンショット・画面録画・画面共有(ミラーリング)によって端末外へ持ち出されることを技術的に抑止または検知する実装を指します*1*4。金融アプリの口座情報画面や医療アプリの診療記録、社内情報アプリの人事データなどが主な対象です。
AndroidのWindowManager.LayoutParams.FLAG_SECURE(以下FLAG_SECURE)は、該当するウィンドウのスクリーンショット取得と非セキュアディスプレイ(外部キャスト先など)への表示を抑止するウィンドウフラグです*1。一方でiOSには、スクリーンショットの取得自体を技術的にブロックする公開APIは用意されておらず*5、撮影されたことを検知して事後に対処する設計が基本になります。この非対称性を理解しないまま「両OSで同じ実装ができる」という前提で要件定義を進めると、後工程で仕様の作り直しが発生しやすくなります。
Android FLAG_SECUREの仕組みと制約
FLAG_SECUREは、AndroidのWindowフラグの1つです。Android Developersの説明によれば、このフラグを設定したウィンドウは、バックグラウンドでのスクリーンショット取得を許可せず、非セキュアディスプレイへの表示もブロックします*1。設定対象は画面(Window)単位で、機密性の高いActivityにだけ限定して適用できます。
実装はActivityのonCreate内で、対象Windowに対して次のようにフラグを立てる形が基本です。
window.setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
)
この設定によって、ユーザーがスクリーンショットを撮影しても結果は空白画像になり、外部ディスプレイへのキャスト(Miracast等)や画面録画アプリでの取り込みも防がれます*1。加えて、アプリをバックグラウンドに回したときにOSが生成するタスク一覧(最近使ったアプリ)のサムネイルも、同じ仕組みで空白表示になります。
ただし制約もあります。Android Developersは、FLAG_SECUREだけではオーバーレイ攻撃への対策として十分ではなく、Android 12以降で追加されたHIDE_OVERLAY_WINDOWS権限の併用を推奨しています*1。また、Android 11以前の端末では一部で信頼性に差があり、意図どおりに機能する割合が限定的だったことも明記されています*1。設計時は「FLAG_SECUREを付ければ終わり」ではなく、対象OSバージョンの範囲と、想定する攻撃経路(正規の画面共有アプリの悪用か、悪意あるオーバーレイアプリか)を切り分けて検討する必要があります。
iOSにおけるスクリーンショット・画面録画の検知
iOSでは、Androidのようにスクリーンショット取得そのものを技術的にブロックする公開APIは提供されていません*5。Apple Developer Documentationが示す仕組みは「検知して対処する」方式です。ユーザーがスクリーンショットを撮影すると、システムはUIApplication.userDidTakeScreenshotNotificationという通知を発行します*4。アプリはこの通知をNotificationCenterで監視することで、撮影の事実を把握できます。
ただしこの通知は撮影後に届く事後通知であり、撮影自体を止めることはできません*4。アプリ側でできる対応は、撮影を検知した後にログを記録する、利用規約違反として警告を表示する、機密情報を含む画面であれば再表示時にマスクをかけるといった事後的な措置に限られます。
画面録画・画面ミラーリング・AirPlayによる外部出力については、別の仕組みが用意されています。UIScreen.isCapturedプロパティは、システムが画面を他の出力先に複製している最中かどうかを示すブール値です*6。ただしこのプロパティはiOS 11以降で非推奨とされており、Apple Developer Documentationは後継としてsceneCaptureStateの使用を案内しています*6。キャプチャ状態が変化したタイミングはUIScreen.capturedDidChangeNotificationで通知されるため、録画開始を検知した瞬間に該当画面へ目隠しを重ねる、といった実装が可能です*3。
Androidの新しいバージョンにも、検知に特化したAPIが追加されています。Android 14ではActivity.ScreenCaptureCallbackが導入され、registerScreenCaptureCallbackでコールバックを登録すると、ユーザーがスクリーンショットを撮影した際に通知を受け取れます*2。利用にはDETECT_SCREEN_CAPTURE権限の宣言が必要で、コールバックは撮影された画像自体を提供しない仕組みです*2。FLAG_SECUREが「抑止」であるのに対し、こちらは「検知」であり、メッセージアプリで会話のスクリーンショットを相手に通知する用途などが想定されています*2。
秘匿表示とisSecureTextEntryによる保護
画面全体のキャプチャ対策に加えて、入力フィールド単位で情報を秘匿する方法もあります。UIKitのisSecureTextEntryは、テキストオブジェクトのコピーを無効にし、場合によっては録画・配信を妨げ、テキストを隠す機能を持つブール値のプロパティです*7。パスワード入力欄で標準的に使われる設定ですが、この仕組みを応用し、任意のビューをセキュアな入力欄でラップして画面キャプチャから保護する実装パターンも知られています。
アプリがバックグラウンドへ遷移する瞬間の秘匿表示も、実務では欠かせない対応です。Apple Developer Technical Q&A QA1838は、アプリがバックグラウンドに入る直前にシステムがウィンドウのスナップショットを撮影し、それがタスクスイッチャー(アプリ切り替え画面)に表示される仕組みを説明しています*8。この資料では、スナップショット撮影前に呼ばれるapplicationDidEnterBackgroundのタイミングで単色の目隠しビューを表示し、フォアグラウンド復帰時のapplicationWillEnterForegroundで取り除く実装例が示されています*8。SwiftUIアプリでもSceneDelegateのsceneWillResignActive・sceneDidBecomeActiveに相当する処理を使い、同様の目隠しを実装するのが一般的な設計です。
ここで注意したいのは、目隠しビューをアニメーション付きで表示すると、スナップショット撮影のタイミングに間に合わない場合がある点です*8。QA1838でも、アニメーションを使わずに即座に表示・非表示を切り替える実装が推奨されています*8。この種の細部は公式ドキュメントを確認しないまま実装すると見落としやすく、金融・医療系アプリの審査やセキュリティ監査で指摘されやすいポイントです。
Android・iOSの実装アプローチ比較
ここまで見た内容を踏まえ、AndroidのFLAG_SECUREとiOSの検知方式を対比します。両OSで実装思想が根本的に異なるため、要件定義の段階でこの違いを発注者・開発者双方が共有しておくことが、手戻りを防ぐ観点で重要です。
| 観点 | Android(FLAG_SECURE) | iOS(検知+秘匿) |
|---|---|---|
| スクリーンショット | 撮影を抑止し空白画像になる*1 | 撮影は止められず、撮影後に通知を受け取る*4 |
| 画面録画・ミラーリング | 同じフラグで非セキュア出力先への表示を抑止*1 | キャプチャ状態の変化を検知し、都度目隠しを重ねる*3*6 |
| 実装の主体API | WindowManager.LayoutParams.FLAG_SECURE*1。Android 14以降はScreenCaptureCallbackで検知も可能*2 | UIApplication.userDidTakeScreenshotNotification、UIScreen.capturedDidChangeNotification*4*3 |
| タスク一覧のサムネイル | FLAG_SECURE設定画面は自動的に空白化*1 | バックグラウンド遷移時に目隠しビューを自前で実装する必要がある*8 |
| 留意点 | オーバーレイ攻撃への対策は別途HIDE_OVERLAY_WINDOWS権限が必要*1 | 目隠し表示はアニメーションなしで即時に切り替える必要がある*8 |
実装で見落としやすい落とし穴
画面キャプチャ防止の実装は、机上の設計と実機での挙動が食い違いやすい領域です。特定のOSバージョンや端末メーカーのカスタムROMで、FLAG_SECUREの効き方に差が出る場合があるため、対象端末の範囲を絞って実機検証する工程を計画に含める必要があります*1。検証を省略したまま本番リリースすると、想定外の端末で機密画面がキャプチャ可能な状態のまま公開されるリスクがあります。
iOS側では、目隠しビューの実装漏れが典型的な失敗パターンです。applicationDidEnterBackgroundの実装を追加しても、対象にすべき画面(決済確認、個人情報の一覧表示など)を洗い出せていないと、一部の画面だけタスクスイッチャーに機密情報が映り込む状態が残ります*8。対象画面の棚卸しと、開発後のUIレビューを工程に組み込むことが欠かせません。
内製でこの領域を担う場合、AndroidのWindow/Activityライフサイクルの知識、iOSのUIKit/SceneDelegateのライフサイクル知識、両OSのセキュリティAPIの仕様変更を継続的に追う体制の3つが必要になります。エンジニア1名がAndroid・iOS両方を兼務する体制では、OSバージョンアップ時の仕様変更(本稿で触れたisCapturedの非推奨化のような変更*6)への追随が遅れ、脆弱な状態が長期化する懸念があります。
外注と内製、判断の分かれ目
画面キャプチャ防止機能自体の実装量は、他の機能に比べて大きくはありません。判断の分かれ目になるのは、実装後の継続運用です。OS側のセキュリティAPIは今後も見直しが続く領域であり、本稿執筆時点でもUIScreen.isCapturedの非推奨化とsceneCaptureStateへの移行*6、Android 14でのScreenCaptureCallback追加*2といった変更が起きています。こうした変更を継続的に把握し、既存実装への影響を都度判定する体制を自社だけで維持できるかが、外注・内製を分ける実務上のポイントです。
専門パートナーに依頼する場合は、Android・iOS双方のセキュリティAPIの動向を横断的に追っている体制かどうかを確認するのが有効です。内製で完結させる場合は、モバイルOSのセキュリティ関連アップデートを定期的にレビューする担当を明確に決め、リリースのたびに対象画面の一覧を突き合わせる運用ルールを設けることが、機能の形骸化を防ぐ鍵になります。
金融・医療・社内情報システムのように機密情報を扱うアプリでは、画面キャプチャ対策の不備が情報漏えいインシデントに直結します。要件定義の段階で「どの画面を対象にするか」「両OSでどこまで挙動をそろえるか」を発注者・開発側で合意しておくことが、後工程の手戻りとセキュリティリスクの両方を抑える出発点になります。
まとめ:画面キャプチャ防止の3つの判断軸
本稿ではモバイルアプリの画面キャプチャ防止について、AndroidのFLAG_SECUREとiOSの検知型アプローチの違いを中心に整理しました。要点は3つに集約できます。第一に、AndroidはFLAG_SECUREによる抑止が可能な一方、iOSには同等の技術的ブロック手段が無く検知・秘匿による対応が基本になる点です*1*5。第二に、対象画面の棚卸しと実機検証を工程に組み込まなければ、対策の抜け漏れが残りやすい点です。第三に、OS側のセキュリティAPIは継続的に変化するため、実装後も追随できる体制の有無が外注・内製の判断軸になる点です。
よくある質問
iOSでもAndroidのFLAG_SECUREのようにスクリーンショットを技術的にブロックできますか。
現時点のApple公式ドキュメントには、スクリーンショット取得自体を防ぐ公開APIは案内されていません*5。iOSでは撮影を検知するuserDidTakeScreenshotNotificationを使い、事後にログ記録や画面のマスク表示で対応する設計が中心になります*4。
FLAG_SECUREを設定すると、通常のアプリ利用に影響はありますか。
FLAG_SECUREは指定したWindowにのみ適用されるため、機密性の高い画面だけに限定して設定できます*1。ただしバックグラウンド移行時のタスク一覧サムネイルも同時に空白化されるため、対象画面をどこまで広げるかは事前に決めておく必要があります*1。
画面キャプチャ防止機能の実装には、どのくらいの期間がかかりますか。
機能そのものの実装範囲は限定的ですが、対象画面の洗い出しや実機での挙動確認を含めると相応の工数が発生します*1。既存アプリへの追加か新規開発かによっても変わるため、対象画面数を踏まえて個別に見積もる必要があります。
画面キャプチャ防止と生体認証やデータ暗号化は同じ対策として扱えますか。
扱う領域が異なるため、同一の対策とはみなせません。画面キャプチャ防止は表示中の画面情報の持ち出しを防ぐ対策であるのに対し、データ暗号化は保存データの保護、生体認証は本人確認を担う対策です。機密情報を扱うアプリでは、これらを組み合わせて多層的に設計することが有効です。
Android・iOSどちらのOSでも同じ実装コードを使い回せますか。
使い回せません。AndroidはWindowフラグによる抑止型のAPIであるのに対し*1、iOSは通知の監視と目隠しビューによる検知・秘匿型の実装になるため*4*8、OSごとに個別の設計・実装が必要です。
著者:テレリモ総研編集部 鈴木 亮佑
ご不明な点はお問い合わせフォームからもご連絡いただけます。
- *1 出典:Android Developers「Secure sensitive activities」
- *2 出典:Android Developers「Detect when users take device screenshots」
- *3 出典:Apple Developer Documentation「UIScreen.capturedDidChangeNotification」
- *4 出典:Apple Developer Documentation「UIApplication.userDidTakeScreenshotNotification」
- *5 出典:Apple Developer Documentation「UIApplication」(スクリーンショット取得を技術的にブロックする公開APIは提供されていない)
- *6 出典:Apple Developer Documentation「UIScreen.isCaptured」
- *7 出典:Apple Developer Documentation「isSecureTextEntry」
- *8 出典:Apple Developer Technical Q&A「QA1838: Preventing Sensitive Information From Appearing In The Task Switcher」