コンテンツにスキップ

Flutterアプリのセキュリティチェックリスト

フェーズ0: ガバナンス、環境、CI/CD

CIゲートの強制

  • 各PRで静的解析を実行:flutter analyze、単体/UIテスト、dart pub outdated
  • SAST/SCA/DASTでHigh/Criticalの検出があった場合はリリースをブロック。リリースブランチではLinterエラーゼロを義務付ける。

シークレットの処理

  • Dartソースコード、pubspec.yaml、ネイティブコード、またはログにシークレットがないこと。
  • ビルド時の設定注入には環境変数(例:--dart-define)を使用する。
  • アナリティクス(analytics)のシークレットを編集(マスク)する。
  • キー/トークンを定期的に、および漏洩が疑われる場合にローテーションする。

エビデンスとトレーサビリティ

  • スキャンレポート、SBOM、ビルドログ、およびリリースノートを各アーティファクトとともにアーカイブする。

Scanning automation

  • モバイル用SAST/DAST/SCAプラットフォーム(Flutter対応)をCI/CDに統合し、各PRおよびプレリリースで実行し、High/Criticalの問題で自動的にゲートをフェイルさせる。

フェーズ1: 脅威モデリング、データ分類、およびインベントリ

  • データ(PII、認証情報、トークン、支払い)を分類し、収集、処理、保存(ファイル、安全なDB)、送信をマッピングする。
  • 信頼境界(trust boundaries)を特定する(Dart環境/Isolate、MethodChannel、ネイティブライブラリ、プラグイン、バックエンドAPI)。
  • サードパーティの pub.dev パッケージのインベントリを作成。適切に保守・検証された公開者(verified publishers)であり、最小権限のプラグインを優先する。
  • Dartパッケージの攻撃面を最小限に抑える。

Phase 2: Build and configuration hardening

Release settings

  • すべての本番ビルドがAOTを有効にしたリリースモード(flutter build apk/ios --release)でコンパイルされていることを確認する。
  • 本番ビルドから開発用エンドポイントと機能フラグ(feature flags)を削除する。

Android specific

  • Gradleで minifyEnabled true および shrinkResources true を使用する。
  • AndroidManifest.xml に必要な権限のみを宣言する。
  • networkSecurityConfig で平文トラフィックを無効にする。

iOS specific

  • デバッグシンボルとデッドコードを削除(ストリップ)する。
  • 必要なエンタイトルメントのみを付与する。
  • Info.plistNSAllowsArbitraryLoads = false を設定する。

Phase 3: Local storage and secure storage

セキュアストレージ

  • すべてのトークン、機密性の高いPII、および暗号化キーには flutter_secure_storage プラグイン(または同等のもの)を使用する。
  • Android:プラグインがKeystoreでバックアップされた暗号化(EncryptedSharedPreferences)を使用していることを確認する。
  • iOS:プラグインが適切なアクセス可能性設定(例:kSecAttrAccessibleWhenUnlockedThisDeviceOnly)でKeychainを使用していることを確認する。

Files and databases

  • シークレットや機密性の高いPIIを平文で SharedPreferences やローカルファイルに保存しない。
  • 機密データを保存する場合は、データベース(SQLCipher付きのsqfliteなど)を暗号化する。
  • シークレットをログに(一時的であっても)書き込まない。

Caches and derived data

  • PIIをキャッシュ/一時ディレクトリに永続化しない。
  • ログアウト時にキャッシュ/一時ディレクトリをパージする。

Phase 4: Privacy safeguards (UI, clipboard, screenshots)

  • アプリスイッチャーで機密UIを非表示にする(例:secure_application プラグインを使用するか、画面をぼかす/隠すネイティブコードを使用)。
  • アプリ起動時のクリップボードの読み取りを避ける。
  • パスワード、キー、長寿命のトークンをシステムクリップボードに絶対に入れない。

Phase 5: Network security and TLS/pinning

HTTPS/TLSの強制

  • すべてのアプリ通信にHTTPSを強制する。DartのデフォルトのHTTPクライアントはTLSを強制しますが、不正な証明書を拒否するように設定する必要があります。
  • 本番環境で証明書チェックを絶対にバイパスしない(badCertificateCallback)。

証明書ピンニング

  • SSL/TLS証明書のピニングを実装する(例:SecurityContext オブジェクトでSHA-256をチェックすることによって)。
  • MITMのシナリオおよび期限切れ/ローテーションされたリーフ(leaf)証明書に対する耐性を検証する。
  • 安全なピンローテーションとフォールバック(バックアップ)を計画する。

Cookies and tokens

  • デバイス上の長寿命のベアラートークン(bearer tokens)を避ける。

フェーズ6: 認証、認可、セッション

認証フロー

  • パブリック認証フローにはPKCEを伴うOAuth2/OIDCを使用する(例:flutter_appauth を使用)。
  • クライアントシークレットや認証関連のAPIキーをDartのソースコードに絶対に埋め込まない。
  • 認証には、アプリ内のWebViewよりもシステムブラウザコンポーネント(Chrome Custom Tabs、SafariViewController)を優先する。

トークン

  • 短寿命のアクセストークン(access tokens)を使用する。
  • リフレッシュトークン(refresh tokens)を安全に保存する(例:flutter_secure_storage)。
  • ログアウト、デバイス変更、不審なアクティビティの際にトークンをローテーションおよび無効化する。

認可 (Authorization)

  • サーバー側の認可(authorization)を強制する。Flutterアプリの状態は信頼できない(untrusted)ものとして扱う。

  • 可能な場合は、カスタムURLスキームの代わりにAndroid App LinksとiOS Universal Linksを使用する。
  • すべての受信リンクの送信元とパラメーターをDartコード内で検証する。

Custom schemes and intents

  • カスタムスキームを使用する場合は、すべての受信データとデータ型の堅牢な検証を確実にする。
  • URLハイジャックとオープンリダイレクトを防御する。

Phase 8: Reverse engineering and tamper resilience

Code obfuscation

  • FlutterのリリースモードでDartがネイティブAOTコード(Android/iOS)にコンパイルされていることを確認する。
  • ビジネスロジックとクラス名を隠すために、Flutterの難読化サポート(flutter build apk --obfuscate --split-debug-info=/<dir>)を使用する。

環境チェック

  • 信頼できるプラグイン(flutter_jailbreak_detectionfreeraspなど)を使用して脱獄(iOS)とルート化(Android)を検出する。
  • 疑わしい環境に対して比例的(機能制限、警告、または終了)に対応する。

Anti-tamper

  • バックエンドでの構成証明(attestation)のために、ネイティブの完全性チェック(Androidの場合はPlay Integrity API、iOSの場合はDeviceCheck/App Attest)に依存する。
  • クライアント側のチェックはシグナルとして扱い、唯一のセキュリティコントロールとして扱わない。

Phase 9: Cryptography and randomness

  • 精査されたDartの暗号化実装(例:cryptopointycastle パッケージ)を使用するか、MethodChannelを介してネイティブプラットフォームのプリミティブに任せる。
  • Dartの暗号論的に安全なRNG(Random.secure())を使用する。
  • 対称暗号化には最新のモード(AES-GCMなど)を使用する。
  • IVまたはハードコードされた暗号化キーを絶対に再利用しない。

Phase 10: Permissions, notifications, and identifiers

Privacy‑related permissions

  • アプリのコンテキストの明確な説明を伴って、使用時(point-of-use)に権限を要求する。
  • デバイスのセンサー(位置情報、カメラ、マイク)へのアクセスを厳密な必要性に制限する。

Identifiers

  • デバイスのハードウェアIDのバインディングを避ける。アプリ固有のリセット可能な識別子を使用する。

通知

  • プッシュ通知のペイロード内の機密データを最小限に抑える。開いたときのフェッチ(fetch-on-open)に依存する。

Phase 11: Logging, analytics, and crash reporting

ロギングの衛生管理

  • リリースビルドでデバッグログとDartの print() を無効にする(Flutterのfoundation APIの kReleaseMode / kDebugMode を使用)。
  • アナリティクスイベントとクラッシュレポート(Firebase Crashlytics、Sentryなど)からPIIとシークレットを編集(マスク)する。
  • 難読化マッピングファイル(--split-debug-info)がクラッシュの難読化解除のためにサーバー側に安全に保管され、アプリと一緒に出荷されないことを確認する。

Phase 12: Testing, DAST, and runtime verification

Interception tests

  • アプリのMITM攻撃に対する耐性を検証する(特別な信頼設定なしでプロキシが傍受した場合に、Dartのネットワーク接続が失敗することを確認する)。

API悪用テスト

  • FlutterアプリをサポートするバックエンドAPIに対して、レート制限の欠如、大量割り当て(mass assignment)、および認可の脆弱性(IDOR/BOLA)をテストする。

Dynamic analysis

  • モバイルDAST(DartのHTTPクライアントトラフィックを検査する)を実行して、構成の誤ったAPIとデータ漏洩を特定する。
  • トリアージおよび再テストのためのDASTの証拠をエクスポートする。

Phase 13: SBOM, and evidence

SBOMと依存関係

  • Dart依存関係とネイティブコンポーネント(pubspec.yamlbuild.gradlePodfile)の脆弱性を監視する。
  • Flutter/DartパッケージのSBOMを生成する。

エビデンスバンドル

  • 分析(SAST/DAST)アーティファクトをリリース記録に添付する。
  • SBOMをリリース記録に添付する。

実務者向けクイックリファレンス

  • Config: AOTリリース。ログ/エンドポイントを隠すために kReleaseMode を使用。--obfuscate をオンにする。
  • Data: 常に flutter_secure_storage またはネイティブの暗号化ブリッジを使用。prefs/SQfliteに平文のPIIを入れない。
  • Network: 常にHTTPS。SecurityContext を介して証明書をピニング。本番環境でバイパスするための badCertificateCallback を使わない。
  • Auth: OAuth(flutter_appauth)にはシステムブラウザ + PKCEを使用。ハードコードされたシークレットなし。
  • Tamper: ルート/脱獄の検出(freeraspなど)、バックエンドの構成証明(Play Integrity / DeviceCheck)。
  • Privacy: バックグラウンドのスクリーンショットをぼかす。クリップボードデータをクリア。JITで権限を要求する。
  • Dart/Flutter: 認可の決定においてフロントエンドを信頼しない(API must verify)。承認された制限付きの pub.dev パッケージに依存する。