はじめに
こんにちは。Androidエンジニアのgottieです。
個人開発でCloud Functions(GCP)を使ってみたのですが、APIのアクセス制限の方法が少しやっかいだったため記事にしておきます。
やりたいこと
特定のAndroidアプリからからのみ、GCPのAPI呼び出しを行えるようにしたいです。
やったこと
1 APIキーの作成
GCPの「APIとサービス」から「認証情報」>「認証情報を作成」>「APIキー」を選択します。
作成したAPIキーの詳細に移動すると以下の画面が表示されます。
2. アプリケーションを制限する(ここ重要)
このステップで特定のAndroidアプリからのみ呼び出すことができるようにします。ラジオボタンの「Androidアプリ」を選択して、使用するアプリのパッケージ名とSHA-1証明書のフィンガープリントを入力します。
画面右側に各OSでフィンガープリントを出力するコマンドが出ていますがここに罠があります。
試しに以下のコマンドを入力とその結果です。(結果は桁数以外は適当です。)
keytool -list -v -keystore debug.keystore -alias androiddebugkey -storepass android -keypass android
MD5: 33:01:38:7E:90:0A:C9:64:41:C8:B5:BE:CE:24:D2:D8:2D:2B:EE:41
SHA1: AB:CD:12:34:56:78:EF:F8:B9:C0:C5:8B:B0:E2:54:21:39:A3:73:BD:9B:62:87:4A:A9:D5:A2:5D:0D:6D:21:4D
SHA256: SHA256withRSA
このSHA1の結果をそのまま入力すると、SHA-1 署名証明書フィンガープリントが無効です
と赤文字で表示されます。
実はこれkeytool
のバグっぽくてこちらにも記載がありますが、MD5の場所にSHA-1が、SHA-1の場所にSHA-256が記載されているのかなと思われます。なのでGCP側のSHA-1の入力欄にはkeytoolで表示したMD5の方を入力しましょう。
まぁよく考えればSHA1は160bitなので桁数的におかしいですね。(いや、気づかねーよ!)
(SHA-256は256bitなのでSHA-1に表示されているものと一致しますね。)
3.APIの制限
こちらは今回の記事とは直接関係ないですが、設定しておいた方が良いと思われます。
4.Androidからリクエストを投げる。
ここまででGCP側の設定は終了です。GCP側はAndroidアプリの〇〇からのリクエストは許可するよ~っていう状態なので、Android側はリクエストの際、自分は〇〇っていうアプリだよってことを教えてあげないといけません。今回はOkHttpを使用します。
リクエストヘッダーにX-Android-Package
とX-Android-Cert
を追加し、それぞれパッケージ名とSHA-1を入れてあげればよいです。パッケージ名や署名のSHA-1の取得方法はいくつかあるようですが、こちらを参考にしました。
ちなみにsha1のフィンガープリントを入力する際はコロンは不要のようです。
val request = Request.Builer().apply {
url(YOUR_GCP_URL_WITH_API_KEY)
addHeader("X-Android-Package", packageName)
addHeader("X-Android-Cert", cert)
}.build()
val response = OkHttpClient().newCall(request).execute()
これで無事GCPのAPIを安全に特定のAndroidアプリからのみ呼び出せるようになりました!
おわりに
パッケージ名とSHA-1をリクエストヘッダーに入れるのだろうな~と思ってはいたのですが、なかなかこの情報を見つけることができなくて、少し苦労しました。(GCPの公式にX-Android-Package
やX-Android-Cert
の情報あります?)
今回は触れなかったですが、もしかして、OAuthを使ったりするのかな?
とりあえずGCPの呼び出しをうまく制限できたのでやりたいことはできたということで以上です。ではまた。
参考
API キーの使用
keytoolの翻訳バグに遭遇した話
How does google verify Android SHA1 fingerprints and packages?
5分でわかるSSL通信 SHA-1、SHA-2の違いとは?