Closed10

Flutter(モバイル)アプリでのAPIキーなどをセキュアに扱う方法について

tristartristar

ネットで調べていると、APIキーなどを格納するために flutter_dotenv などを使い.envに格納するという記述があるものの、別の記事では「この方法はapkをunzipすることで確認できてしまうため不十分」と記載がある。
実際にそうなのか確認してみる。

参考:
How to Store API Keys in Flutter: --dart-define vs .env files

tristartristar

調べてみた結果は以下の通り。

  • .envには機密性の高いキー情報は含めるべきではない
    • envied などのパッケージを使用して難読化することは出来る
  • Firebase, GoogleMapのAPIキーはクライアントに埋め込むことが出来る。
    • 不正な利用の回避は主にセキュリティルールやAPIキーの制限で制御する
  • Dartも含めたソースコードの難読化はリリースビルドでは常に行っておいた方が良い
tristartristar

assets/.envにダミーの変数を定義、アプリをReleaseモードでビルドしてみる。

build/app/outputs/apk/release/app-release.apk が生成されるので、
これをunzipする。

unzip app-release.zip

色々と展開される中にassetsフォルダも含まれていて、ここでそのままの.envファイルが含まれているのが確認できる。

apktool を使い以下のコマンドを実行することで逆アセンブルが出来るらしく、
この方法でも同様に assetsフォルダ内にそのままの.envが含まれることが確認できた。

apktool d app-release.apk
tristartristar

assetsフォルダ配下に置く時点で、こうなりそうな気はしていた...。

tristartristar

FirebaseのAPIキーについては、公式にもクライアントに埋め込むことが出来るもの(その上でセキュリティルールを使用して制限する)と記述があるので、Firebaseの場合は「APIキーとは言ってもプロジェクトを特定するためのキー的なもの」なのだと思った。

なので、セキュリティルールに注意する必要がある。
※ただし、パスワード認証に対しブルートフォース攻撃を仕掛けられるようなことを避けるため特定のケース ではクォータを締めるなどして対策する。

tristartristar

Amplifyの場合はどうなるのか試したことがないので分からない。

tristartristar

元の記事を見ていると、.envを使用する場合は Enviedというパッケージを使用して .env自体の難読化を行うことが案として挙がっている。
.envに機密性の高い情報は含めない方が良いということだったけどこれを行えば解析し難くはなりそう。

また、どの選択をした場合でもコードの難読化は行っておいた方が良い旨が書かれている。
https://codewithandrea.com/articles/flutter-api-keys-dart-define-env-files/#note-about-obfuscation

Firebaseのgoogle-services.json(GoogleService-Info.plist)やGoogleMap APIのAPIキーは
クライアントに埋め込んでも大丈夫そうな物と考えると今時点で機密性の高いキーは自分は持っていなそうなものの、難読化でどの程度変わるのか確認してみる。
(iOSも気になるが手元で確認できないのでAndroidだけ)

tristartristar

以下のコマンドでReleaseモードでビルド、難読化を有効にしてビルドする。

flutter build apk --obfuscate --split-debug-info=obfuscate/android --release --dart-define=FLAVOR=dev

ビルド後のapkを単純にunzipした状態とapktoolで逆アセンブルした状態で、AndroidManifest.xmlなどに埋め込んだAPIキーなども見れるのか確認してみる。

結果は以下の通り

情報 unzipのみ apktool d 備考
.env 閲覧できる 閲覧できる assetsフォルダはどちらの場合もそのまま
Firebase, GoogleMapのAPIキー 閲覧できない 閲覧できる APIキー情報はAndroidManifest.xmlと、res/values/strings.xmlに記録される。apktoolでデコードしないと、AndroidManifest.xmlはバイナリ、res/valuesフォルダは存在しなかった。

APIキーを検索

unzipのみ

apktool d でデコードした結果

unzipしただけだとAndroidmanifest.xmlはバイナリ、res/valuesはフォルダごと存在しない

このスクラップは2022/10/07にクローズされました