シニア デベロッパー リレーションズ エンジニア
このプレゼンテーションでは、AI を一般的なコーディング アシスタントとして捉えるのではなく、Android 開発ライフサイクルに直接統合された、コンテキストを認識する自動セキュリティ ピアレビュー担当者として活用するという戦略的な転換について説明します。スキルを介して Android ツールチェーンに接続された、専門的な AI エージェントが、アプリのセキュリティ向上にどのように役立つかについて説明します。このアプローチは、未加工の LLM 機能と深いプロジェクト コンテキストのギャップを埋めることで、開発チームが厳格なセキュリティとポリシーの基準を損なうことなく、迅速な機能提供を維持できるようにします。
文字起こし
こんにちは、Kristen です。
こんにちは、Sabs です。
本日は、エージェントの時代におけるセキュリティについてお話しします。
昨年、Android Bug Hunters プログラムに 200 万ドル以上、モバイルに 20 万ドル以上の報奨金を支払いました。
エージェントの時代を迎えた今、アプリのセキュリティは常に進化しています。
そこで、これらの問題を迅速かつ効果的に解決するためのツールについて説明します。
Android のセキュリティに関するエージェントのパフォーマンスを改善するには、プロンプトを改善するだけでは不十分です。
これは、エージェントが Google のツールチェーンと API を理解して、アプリの安全性を維持できるようにするためのツールとワークフローです。
午後 4 時 30 分です。
木曜日です。
リリースをカットしているときに、CI が赤色になり、エラーが 1 つだけ表示されます。エクスポート フラグなしで登録されたブロードキャスト レシーバです。
そのため、すべての役割を担う小規模なチームでも、リリース時にセキュリティ チェックが行われる大規模なチームでも、現実は同じです。
私たちはプロダクト エンジニアであり、高品質の機能を迅速にリリースしていますが、必ずしもセキュリティ研究者ではありません。
では、自然な本能とは何でしょうか。
そこで、その警告をエージェント型ツールに渡し、エージェントに修正を依頼します。
しかし、プロジェクトのコンテキストなしで動作するエージェント ツールには、3 つの盲点があります。
アプリが動的機能モジュールまたはマルチ APK バンドルからビルドされていることを認識していない可能性があります。
出荷されたアーティファクトではなく、ファイルとして認識されます。
Kotlin UI から KMP 共有ロジック、ネイティブ C++ JNI 呼び出しまでのデータフローをトレースできない可能性があります。
1 つのレイヤのみが表示されます。
最後に、最小 SDK や Gradle ビルド フレーバーが認識されない可能性があります。
そこで、エージェントにアプリを提示し、セキュリティ監査を依頼しました。
6 件の検出結果が返されました。
ここで重要なのは
どれも間違っていません。
どれも妥当な説明ですが、実際に最初に発生したバグは 1 つだけです。
残りは、ベスト プラクティス、さらに調査が必要な事項、推測、適用されない可能性のある事項が混在しています。
これを実際のコードベースにスケールすると、警告が増え、pull リクエストごとに suppress lint を使いたくなるでしょう。
変更をマージする機会を逃したり、脆弱性を見逃したりする可能性があります。
そして、実際の脆弱性がすり抜けてしまいます。
このツールは不注意ではなく、慎重でしたが、慎重であることは有用であることと同じではありません。
具体的に見てみましょう。
たとえば、エージェントに「このアプリでエクスポートされたすべてのコンポーネントを監査して、アプリ インテントのリダイレクトを確認して」と指示したとします。
これは、セキュリティに関する重要なタスクであり、マルチモジュール アプリでは大規模なタスクになります。
このようなリクエストでは、実際に費用が発生します。
Android 固有のガイダンスがないため、エージェントはその質問に対する戦略を持っていません。
つまり、ブルート フォース攻撃です。
何もエクスポートしないモジュールを読み取ることもあります。
インテント リダイレクトを悪用可能にする要素を、第一原理から再導出する場合があります。
到達できなかったパスをたどる可能性があります。
分析ではなく、探索に費用をかけている。
スキルとは、欠けている戦略を補うものです。
たとえば、Android セキュリティ スキルは、現在のガイダンスに沿った指示をエージェントに提供します。これは、セキュリティ研究者が実際にたどる手順と同じであり、エージェントは推測を停止します。
ルールはスキルによって提供されたものであるため、ルールは再検出されません。
現在、インテント セキュリティと権限という 2 つのセキュリティ スキルがリリースされています。
インテントのセキュリティとは、他のアプリが自分のアプリに何を実行できるかということです。
アプリは、ユーザーが持っていない権限やログイン セッションを保持しています。
そのため、エクスポートされたすべてのコンポーネントと、渡されたすべてのペンディング インテントは、誰かがあなたを介して行動する潜在的な方法となります。
このスキルは、こうした問題を防止する対策に役立ちます。
権限スキルは、宣言された権限と実際に適用される権限のギャップを埋めるのに役立ちます。
適切な権限チェックを作成するのに役立ちます。
ワイルドカード パスを持つプロバイダが、1 つのディレクトリではなくデータベース全体を許可しているかどうかを特定するのに役立ちます。
過剰な権限のリクエストも検出されます。
たとえば、写真選択ツールで十分な場合に、幅広いアクセスをリクエストしている。
Android CLI で使用し、「インテント セキュリティの監査」を依頼します。
設定がありません。
ルールをチューニングしない。
そのため、出力が警告の山になることはありません。
レビューです。
「ここにバグがあります。アプリにとってこれが重要な理由は次のとおりです。修正方法は次のとおりです。」
上級者向けのヒントです。
Android CLI を使用すると、簡単に検索してインストールできます。
android skills list
android skills add android-intent-security
android skills add android-permissions-securityまた、スキルはプロジェクトで何を探すべきかを正確に把握しているため、アプリを実際にリリースされる形で認識します。
最小 SDK を尊重するため、修正はコンパイルされ、実際のファイルパスと実際の行番号が使用されます。
返されたレビューは次のとおりです。
正確なファイルと行を指し示し、Lint がそう言っているからというだけでなく、実際の脅威と変更の理由を説明します。
使用したスキルを引用します。
ビルド構成を読み取り、最小 SDK が 26 であることを確認し、ContextCompat を選択して修正が機能するようにし、適用可能な差分を提示します。
これは、最初に開いた警告ですが、修正案と理由が追加されています。
つまり、前述のスキルはセキュリティ バグを検出するためのものです。
次に、アプリのポリシーへの準拠について説明します。
たとえば、あなたが Google Play ストアでのリリースを目指す新しいアプリ デベロッパーだとします。
データ セーフティ フォームへの記入は、アプリをリリースするうえで重要なステップです。アプリを送信する前に、利用可能なすべてのツールを使用して、フォームに正しく記入されていることを確認しましょう。
Google Play ポリシー スキルは、コードベースの静的分析を実行します。
既存の Google Play ストア アプリを公開する場合は、静的コード分析と Google Play ストアの申告を相互参照することもできます。
このスキルを実行すると、アプリの送信後にではなく、送信前に Google Play ポリシーに関する潜在的な問題を検出できるため、送信プロセスを迅速化できます。
ワークフローは、これまで説明してきた他のスキルと同様です。インポートしてから、「このアプリを送信する前に、Google Play のポリシーに準拠しているかどうかを監査してください」と依頼します。
右側にレポートの例のスクリーンショット、下部にインストール用の Android CLI コマンドが表示されます。
android skills list
android skills add play-policy-insightsここまで説明したことはすべて、インテントの監査、権限の確認、コンプライアンスの検証など、出荷前に行われます。
これはビルド時のセキュリティであり、不可欠なものです。
しかし、APK が世に出て、管理できないデバイスで実行されるようになって初めて存在する脅威のクラスがあります。
Play Integrity API は、実行時に、アプリのコード自体では答えられない 3 つの質問に答えます。1 つ目は、これがアプリの正規の未変更のビルドかどうかです。
正規の Android デバイスで動作しているか。
また、これは Google Play ユーザー アカウントですか?
Play Integrity API を使用すると、アプリの完全性やデバイスの完全性などの判定結果を取得できます。
また、アプリをより安全に、より迅速かつ簡単に公開できるようにするだけでなく、アプリの収益と評判をより簡単に保護できるようにしています。
不正行為や悪用からビジネスを保護しましょう。
こちらの新しい [Google Play による保護] ダッシュボードでは、完全性、配信、収益化の保護を一元的にモニタリング、構成できます。
また、Play Integrity API のウォームアップ レイテンシを短縮することで、速度が重視されるユーザー ジャーニー中にこれらのチェックを使用して、脅威やリスクのあるデバイスをより迅速にブロックできるようにしています。
ここまで、アプリの安全性を維持するための Android の機能とツールについて説明してきましたが、ユーザーについてはどうでしょうか。
まず、SMS OTP 保護について見ていきましょう。
たとえば、アプリに SMS ベースのユーザー確認を実装し、確認コードを送信するとします。
SMS 権限を付与すると、アプリはメッセージ データ(OTP などの機密データを含む)にアクセスできるようになります。
そこで、アプリにいくつかの API を導入して、広範な SMS 権限をリクエストしなくても、確認用の SMS OTP コードを取得できるようにしました。
SMS Retriever API を使用すると、広範な SMS 権限を必要とせずに、アプリで OTP を自動的に検証できます。
アプリを識別する 11 文字のハッシュをメッセージに追加すると、システムはそのメッセージのみを渡します。
メッセージ形式を制御できない場合は、SMS User Consent API を使用します。
システムに 1 回限りのプロンプトが表示されます。
ユーザーが [許可] または [拒否] をタップし、[許可] をタップすると、その 1 つのメッセージが届きます。
この場合も、広範な SMS 権限は必要ありません。
一部のアプリでは、タスクを完了するために正確な位置情報が必要となるのは 1 回だけです。
既存の 1 回だけのアクセス許可はユーザーの負担が大きいため、デベロッパーはより広範な正確なアクセス許可を求めることがあります。
つまり、位置情報ボタンは、アプリに正確な位置情報への 1 回限りのアクセスを許可する、摩擦の少ない方法を提供するツールです。
これは、アプリ デベロッパーがカスタマイズして埋め込むことができる Android UI 要素です。
6 月に、位置情報ボタンの Jetpack ライブラリの最初のアルファ版をリリースしました。
ここでは、Android マニフェストで位置情報ボタンを有効にするために必要な権限を確認できます。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:usesPermissionFlags="onlyForLocationButton"/>
<uses-permission android:name="android.permission.USE_LOCATION_BUTTON" />
<application
android:icon="@mipmap/ic_launcher"
android:label="LocationButtonSample"
android:theme="@style/Theme.PinPoint">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>標準の位置情報の利用許可を宣言する必要があります。つまり、onlyForLocationButton 権限フラグと、システムの遠隔レンダリング サービスに必要な専用の USE_LOCATION_BUTTON 権限を追加する必要があります。
右側は、それを実装する Jetpack コードです。
...
import androidx.core.locationbutton.compose.LocationButton
@Composable
fun LocationPermissionScreen(onPermissionGranted: () -> Unit, onPermissionDenied: () -> Unit) {
// Renders the secure system-trusted Location Button composable
LocationButton(
// Callback triggered when the user taps the secure button and makes a decision on the permission dialog
onPermissionResult = { isGranted ->
if (isGranted) {
onPermissionGranted()
} else {
onPermissionDenied()
}
},
...ここでは、位置情報ボタンを作成し、コールバックを初期化しています。
このコールバックは、ユーザーが位置情報ボタンをタップして、権限を付与するか拒否するかを決定したときにトリガーされます。
高度な保護機能モードは、リスクの高いユーザーやセキュリティ意識の高いユーザーを対象とした機能ですが、誰でも有効にできます。
たとえば、銀行アプリの場合、毎日のユーザーは余分な摩擦を好まないため、すべての送金で追加の多要素認証を強制することはありません。
しかし、高度な保護機能モードがオンになっている場合、アプリは、このユーザーが最大限の保護を望んでいることを認識し、すべての送金で生体認証を自動的に要求できます。
高度な保護機能モードでは、デバイスの保護を強化するために設計された一連の事前定義構成が実装されます。
ここでは、アプリに統合する方法について説明します。
権限をリクエストし、高度な保護機能モードをクエリして、ユーザーが高度な保護機能モードをオンにしているかどうかを、高度な保護機能モード マネージャー システム サービスを呼び出すオンデバイスを使用して確認する必要があります。
class AdvancedProtectionManager() {
// Check the current status
fun isAdvancedProtectionEnabled(): Boolean
// Be alerted when status changes
fun registerAdvancedProtectionCallback(executor: Executor,
callback: Callback)
fun unregisterAdvancedProtectionCallback(callback: Callback)
}
interface Callback() {
// Called when advanced protection state changes
fun onAdvancedProtectionChanged(enabled: Boolean)
}その後、コールバックを登録することで、ランタイムの変更をリッスンできます。
android skills list
android skills add android-intent-security
android skills add android-permissions-securityandroid skills list
android skills add play-policy-insights<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:usesPermissionFlags="onlyForLocationButton"/>
<uses-permission android:name="android.permission.USE_LOCATION_BUTTON" />
<application
android:icon="@mipmap/ic_launcher"
android:label="LocationButtonSample"
android:theme="@style/Theme.PinPoint">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>...
import androidx.core.locationbutton.compose.LocationButton
@Composable
fun LocationPermissionScreen(onPermissionGranted: () -> Unit, onPermissionDenied: () -> Unit) {
// Renders the secure system-trusted Location Button composable
LocationButton(
// Callback triggered when the user taps the secure button and makes a decision on the permission dialog
onPermissionResult = { isGranted ->
if (isGranted) {
onPermissionGranted()
} else {
onPermissionDenied()
}
},
...class AdvancedProtectionManager() {
// Check the current status
fun isAdvancedProtectionEnabled(): Boolean
// Be alerted when status changes
fun registerAdvancedProtectionCallback(executor: Executor,
callback: Callback)
fun unregisterAdvancedProtectionCallback(callback: Callback)
}
interface Callback() {
// Called when advanced protection state changes
fun onAdvancedProtectionChanged(enabled: Boolean)
}