生体認証を導入したいな
ログイン機能において、メールアドレスとパスワードを毎回入力するのは面倒です。一定期間はログイン状態を維持してくれるアプリケーションが大半ではありますが、生体認証を用いると簡単かつよりセキュアになります。
現在Flutterのアプリケーションを作成しており、そこに指紋認証を導入してみた話をしていきます。
利用パッケージと概説
これから記載する2パッケージを用いて、実装を行います。
導入後の操作イメージ
具体的な2パッケージの話の前に、導入後の画面挙動について記載します。
実際に指紋認証対応端末を使われてない方でもイメージはしやすいかと思います。
初回ログイン
- ユーザーはメールアドレスとパスワードを手動入力
- この時点ではまだ認証情報が保存されていない
- ログイン成功後、認証情報を安全に保存
2回目以降のログイン
- 指紋認証のみでログイン可能
- 保存済みのメールアドレスとパスワードを自動的に取得
- ユーザーは入力操作不要
それでは具体的な話をしていきましょう。
local_auth
生体認証自体はこのパッケージを用いて構築します。
This Flutter plugin provides means to perform local, on-device authentication of the user.
On supported devices, this includes authentication with biometrics such as fingerprint or facial recognition.
生体利用を許容する設定
最初にAndroidManifest.xmlで、指紋認証(生体認証)をアプリに対して許可するように設定が必要です。
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
アプリケーションコードの対応
大きく以下3点を行っています。コードは、実装と実際の挙動で共有しています。
- 指紋認証の利用可能性チェック
- 指紋認証の実行
- 指紋認証の有効化/無効化
flutter_secure_storage
Secure storage using Keychain (iOS) and Encrypted Shared Preferences with Tink (Android).
Platform-specific options for encryption and accessibility.
「Keychain(iOS)とTinkを使用した暗号化されたShared Preferences(Android)を使用した安全なストレージ」とのことです。
iOSについては分かってはいませんが、Tinkについて少しだけ調べました。
この後記載していますが、EncryptedSharedPreferencesが非推奨になっており、その代替となるオープンソースの暗号ライブラリのようです。
アプリケーションコードの対応
セキュアストレージなので、必要な作業自体はイメージしやすいです。
- 認証情報の保存
- 認証情報の取り出し
EncryptedSharedPreferencesの非推奨問題
パッケージのExampleでも以下の形となっていますが、このencryptedSharedPreferencesオプションに関して、少し深掘りした方が良さそうだと分かりました。
static const _storage = FlutterSecureStorage(
aOptions: AndroidOptions(
encryptedSharedPreferences: true,
),
iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock_this_device),
);
EncryptedSharedPreferences方式
Androidの EncryptedSharedPreferences API を内部的に使用し、Jetpack Security ライブラリによる暗号化を行います。
EncryptedSharedPreferencesが非推奨
実はこのオプション絡みの話ですが、「非推奨」という情報があります。
以下に添付したリンクを確認いただくと分かりますが、以下のように記載されており、代わりに利用すべきものが記載されていました。
https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences
Use android.content.SharedPreferences instead.
上記の非推奨の話ですが、Kotlin関係の実装だったので、Flutterに関する情報を収集しました。
FlutterのドキュメントとGithub Issueを追ってみた
公式ドキュメントを確認しました。
We have received vague reports that there is a "CBC with PKCS5/PKCS7 padding vulnerability" in some Flutter packages.
As far as we can tell, this is triggered by the HLS implementation in ExoPlayer (the com.google.android.exoplayer2.source.hls.Aes128DataSource class). HLS is Apple's streaming format, which defines the type of encryption that must be used for DRM; this isn't a vulnerability, as DRM doesn't protect the user's machine or data but instead merely provides obfuscation to limit the user's ability to fully use their software and hardware.
ExoPlayerのHLS実装(com.google.android.exoplayer2.source.hls.Aes128DataSourceクラス)によってトリガーされています。
HLSはAppleのストリーミング形式であり、DRMに使用しなければならない暗号化のタイプを定義しています。これは脆弱性ではありません。
なぜなら、DRMはユーザーのマシンやデータを保護するものではなく、単にユーザーがソフトウェアとハードウェアを完全に使用する能力を制限するための難読化を提供するに過ぎないからです。
続けて、関係が深い2つのIssueです。
App uses CBC with PKCS5/PKCS7 padding
1.Mobile Security Framework (MobSF)でハイリスク判定
Mobile Security Framework (MobSF) reports high risk error that comes from the android part of package.
Mobile Security Frameworkですが、Androidアプリ(apkファイル)の静的解析ツールです。
2.keyCipherAlgorithmとstorageCipherAlgorithmのパラメータ設定はしても変わらず
以下のように実装すれば、ハイリスクが解消されるはずだけどそうならない、というコメントです。
I am using this code but still get the same issue.
static const _storage = FlutterSecureStorage(
aOptions: AndroidOptions(
keyCipherAlgorithm: KeyCipherAlgorithm.RSA_ECB_OAEPwithSHA_256andMGF1Padding,
storageCipherAlgorithm: StorageCipherAlgorithm.AES_GCM_NoPadding,
)
);
3.この問題を解消するには?
so what is the most secure and reliable way for me to use because we are developing mobile app and we are stuggling when we scan the app in mobsf and receive a vuln indicating PKCS7 PADDING is vuln to oracle padding attack
Mobile Security Framework (MobSF)を用いた解析ですが、上記の2対応後に解析を実施してみたところ、確かにハイリスク扱いで表示されました。
[Android] [Beta] Version 10 - Full migration to custom implementation of SecureSharedPreferences
A long outstanding problem with the Android part of this package is the deprecated usage of older cryptography usage (CBC with PKCS5/PKCS7 padding) for SDK < 23, and the already deprecated JetSec Crypto library that is being used for the current implementation of SecureSharedPreferences.
このパッケージのAndroid部分における長年の未解決問題は、SDK 23未満で古い暗号化方式(CBCとPKCS5/PKCS7パディング)が使用されていることと、SecureSharedPreferencesの現在の実装で使用されているJetSec Cryptoライブラリがすでに非推奨になっていることです。
To fix these issues, i am moving to a custom implementation of the JetSec Crypto library, and removing all other deprecated methods of encrypting the shared preferences. This requires the minimum SDK to be raised from 21 to 23.
これらの問題を解決するため、JetSec Cryptoライブラリのカスタム実装に移行し、共有設定を暗号化する他のすべての非推奨メソッドを削除する予定です。これには、最小SDKを21から23に引き上げる必要があるようです。
現在も対応中で、バージョン10のリリース時には対応完了予定といった話でした。
リリースを待つことにします。
メジャーバージョンが10がリリース(2025/12/10)
記事公開の3日前だったため、まだ対応完了までは至っていませんが、12月10日にメジャーバージョン10がリリースされていました。
現在確認を進めています。
(MobSFの「偽陽性」という情報もあるので、詳細を確認中)
アプリケーションの話
ここまで利用パッケージの話を記載してきましたが、具体的なアプリの話に進みます。
前提
複数の認証パターンを試したいこともあり、下記2つとも導入していますが、今回の指紋認証と関係するのは、1の方です。
1.メールアドレスとパスワードによるログイン認証
2.Googleアカウントによるソーシャルログイン認証
画面操作手順
図示すると、以下のようになります。(※)

※このスライドについては、生成AI(glm-4.6)に作成してもらいました。
1枚だけのスライド作成もやってくれるのはありがたいです!
実装と実際の挙動
上記スライドの内容通りの実装です。(ここは普通に実装しています。)
500行くらいあるのでGistにしました。よろしければ参考にしてください。
https://gist.github.com/eno-conan/64b270648ff82f963f86352b7c09275a
また指紋認証が機能しているところを共有しようとしたのですが、セキュリティ観点からかと思いますが、直接スクリーンショットは取れませんでしたので、別端末から撮影しました。
まとめ
今回は指紋認証(生体認証)について、学習してみました。
ソーシャルアカウント認証構築よりもはるかに短時間で構築ができました。ある日の業後だけで完成したので、3時間前後だったかと思います。
開発中はGithubのIssueコメントにどういった形で進めたいか記載をして、Claudeに土台は作成してもらいました。
その内容で動作確認や気になる点を確認となるので、開発時間はかなり短く済みますね。
Flutterのアプリケーションについて、色々整備している最中なので、今後もFlutter関係の記事を公開していきたいと思います。ありがとうございました。
参考





