Firebase Functionsのhttpsトリガーの関数を特定の人からしかできないように制限したい
はじめに
Firebase Functionsには様々なトリガーがありますが、httpsのendpointを公開してインターネットのどこからでもAPIのように利用することもできます。一方で、公開されたfunctionは単純に実装・公開した場合、全世界にフリーに公開している状態になりセキュリティー的に問題がある場合があります。ここでは、いくつかのアクセスを制限する方法を紹介していきます。
1. functions.https.onCallを利用する
The Cloud Functions for Firebase client SDKs let you call functions directly from a Firebase app. To call a function from your app in this way, write and deploy an HTTPS Callable function in Cloud Functions, and then add client logic to call the function from your app.
引用元: callable
Firebase Appの認証状態を利用してCloud Functionsを叩くことができるようになります。前提として Firebase SDKの利用 があるため、Firebase SDKが利用できる環境下に限られてはいますが基本的な用途には必要十分で、とても便利です。
firebase authenticationのcustomClaim機能や、firebaseのデータベースと連動したり、他の機能との組み合わせを工夫をすればユーザー毎の権限で、その関数を実行できるか等のハンドリングも可能になります。
code: functionExample.js
exports.grantRole = functions.https.onCall(async (data, context) => {
const user = await admin.auth().getUser(context.auth.uid);
if (user.customClaims && user.customClaims.admin !== true) {
return false;
}
const email = data.email;
const result = await grantRole(email, 'admin');
return result;
});
上のfunctionsの関数の例ではfirebase authenticationの認証情報、そして簡易的ではありますがcustomClaim機能を利用して関数の利用を制限しています。このように簡単に関数実行の制限を可能となります。
https://gyazo.com/73c541832c2316847eb2a9521e8ccfc5
Functionsの一覧からはこのようにhttpリクエストの関数としてエンドポイントも公開されているため、このエンドポイントが万が一外部に流出した場合誰でもAPIを叩くことはできますが、上記の実装により正常系の処理をさせないことが可能になりました。
2. authorized-https-endpoint を利用する
This samples shows how to restrict an HTTPS Function to only the Firebase users of your app.Only users who pass a valid Firebase ID token as a Bearer token in the Authorization header of the HTTP request or in a __session cookie are authorized to use the function.
引用元: authorized-https-endpoint
公式のExampleに掲載されている実装パターンです。実装は単純で、リクエストヘッダーのauthorizationにfirebase authenticationで作成されたユーザーのidTokenを持たせてリクエストを送ることで、関数内でそのidTokenが正しいものなのかを判断し、関数の実行可否を判断します。
こちらのパターンはリクエストのヘッダーをいじれば良いだけですので、functions.https.onCallが利用できない環境でもAPIを叩けるようにしたい場合に有効です。
実装Sampleは公式の情報が一番わかり易いためそちらを参照してください。function内でexpressを利用するのでそこだけ気をつけてください。
https://github.com/firebase/functions-samples/blob/master/authorized-https-endpoint/functions/index.js
3. authenticated-json-api を利用する
This sample shows how to authenticate access to a JSON API to only allow access to data for a specific Firebase user.Only users who pass a valid Firebase ID token as a Bearer token in the Authorization header of the HTTP request are authorized to use the API.
引用元: authenticated-json-api
こちらも公式のExampleに掲載されている実装パターンです。authorized-https-endpointと似通っているため説明を省略します。こちらも公式の実装Sampleが一番わかり易いのでそちらをご参考ください。
https://github.com/firebase/functions-samples/blob/master/authenticated-json-api/functions/index.js
まとめ
3つの手法を紹介しましたが、FirebaseのアプリやFirebaseSDKを利用するシチュエーションからfirebase functionsを利用する場合は、1. functions.https.onCall が一番手っ取り早いので個人的にはおすすめです。しかしSDKが利用できないシチュエ
ーションの場合は2,3あたりの手法の検討をしないといけません。
例えば、ESP32等のマイコンのモジュールからfunctionsの関数を叩きたいケースの場合、マイコンで利用する言語にはおそらくfirebaseのSDKは用意されていないので、1以外の方法をとる必要がでてきます。今回まさに私がそのケースでしたのでfunctionsのアクセス制限について調べました。
そもそも、関数内にベタ書きでアクセスを制限するようなロジックを書けば問題ないのですが、それだとさすがにダサいということで、ぜひみなさんもかっこよいfunctionsのコードを公式がおすすめする方法で書いてみてくださいね。
#firebase
#cloudFunctions
#firebaseAuthentication