セキュリティルールに必須!〜利用者の特定
Firebase のセキュリティルールを設定する上で必要なポイントは「人」「場所」「出来る事」と言う話を紹介しました。その中の一つの「人」を区別するには、ユーザー認証(ログイン)が必要になります。一見シンプルなログインですが区別の仕方によって作り方も使い方も変わってきます。この記事では、ユーザー認証をどの様に利用するかを紹介します。
どのような「区別」が必要か?
ユーザー認証(ログイン)を利用すれば、使っている人が誰なのかを特定することができます。Firebase のセキュリティルールを設定する上で利用者を区別する必要があるので、ユーザー認証はある意味必須です。しかし、実際にどの様に利用するかで実際のサービスの実装は変わってきます。
前回の記事でも紹介していますが、利用者の区別の方法は幾つかあります。それによってユーザー認証(ログイン)の処理が必要な場所も変わってきます。もちろん、開発するサービスやアプリの機能によってそのやり方も大きく変わってしまいます。そこで、この記事では現在紹介している「ブログサービス」を例に考えてみます。
ブログサービスの場合はユーザー認証は不要!?
Firebase のセキュリティルールを設定するためには、利用者の区別ができれば良いわけです。従って、ブログサービスの場合は、基本は「ユーザー認証」は行わないと言う方法が一般的に使われます。 ユーザー認証を行わないでどうやって区別するかという事ですが、あくまで「基本的に」行わないと言う事です。つまり、一般の利用者は「何もしない=ユーザー認証をしない」と言う方法で区別します。一方で、ブログの記事を投稿する人(サイト運営者/管理者)はユーザー認証を行うことで区別します。サイト運営者(管理者)だけが例外的にユーザー認証(ログイン)を行うと言う事です。
この方法だと
* ユーザー認証をしていないない利用者 → 一般閲覧者(読者)
* ユーザー認証をした人 → サイト運営者(管理者)
と言う形で管理します。
ブログサービスは機能で場所も特定可能
利用者の特定ができると、ブログサービスのセキュリティルールは簡単に決定できます。
それは、アクセスする場所も違うからです! 一般の利用者は、記事を見るページにアクセスすれば良い事になります。基本的には、記事の一覧を表示して、選択した記事を表示するページにアクセスするのは一般利用者という事になります。これらのページでは一切ユーザー認証をする必要はありません。仮にサイトの運営者(管理者)がページを見る場合でも、ユーザー認証をしないで見れば良いだけなので、主な機能の実装にユーザー認証は必要ない事になります。
一方で管理者専用のページを作って、記事の投稿と、一覧を表示して、中身を編集・更新したり、不要な記事を削除できる様にすれば、そのページにアクセスする場合のみ、ユーザー認証(ログイン)をすれば良い事になります。
つまり、場所も機能で分ければ良い事になります。
* 通常のブログ閲覧機能 → ユーザー認証(ログイン)は不要
* 管理用のページ → ユーザー認証を行う
というようにすれば場所の特定も可能です。 できることもシンプルで、通常のブログ閲覧機能は基本的に「読み込みのみ」で良い事になります。 管理用のページは、「読み込み」と「書き込み(新規作成・更新・削除)」という事になります。
一番シンプルな実装は、通常のブログ閲覧機能を作成してインターネットに公開して、ブログの記事の投稿は、Firebase コンソールから Firebase のストレージに作成した記事を直接投稿できるようにすれば、管理用のページは必要ありません。Firebase のコンソールを利用するために、Google のアカウントにログインするのがユーザー認証という事になります。
しかし、この連載で紹介したように、Firebase のデータベースにメタデータを投稿時に保存したりして、利用しやすいサービスにする場合には、管理用のページもしくはアプリが必要になります。その場合には、管理者としてユーザー認証をする事が基本的に必要になります。
考えるのはセキュリティ
当たり前ですが、ログインできれば「管理者になれる」という事です。従って、ユーザー認証(ログイン)のセキュリティを考える必要があります。Firebase のセキュリティルールは、「ユーザー認証済み」だけでもルールは作れますが、セキュリティを考えると「管理者の ID で認証済み」にした方がより高いセキュリティを実現できます。
ユーザー認証だけで「読み込み(read)」と「書き込み(write)」を許可する例
allow read, write if request.auth != null
特定のユーザー ID での認証で「読み込み(read)」と「書き込み(write)」を許可する例
allow read, write: if request.auth.uid == "USER_ID";
一般的な Web サービスでは、最近は「二段階認証」は普通ですが、Firebase の基本機能では現状では二段階認証はサポートされていません。従って、カスタムで実装しない場合には、既存のサービス(Googl や Facebook などの認証)を利用してユーザー認証を行う方法が簡単です。しかし、この方法には問題もあって、サポートする既存のサービスにアカウントを持っていれば Firebase のログイン自体は可能になります。従って、管理者の「特権」を利用するには、「特定の ID」のみできるようなルールにしないと、セキュリティホールになってしまいます。
ブログサービスの場合は、管理者以外のアカウントは不要なので、既存のサービスによる認証を行う場合は管理者の ID 以外の場合は、即時サインアウトするような処理を行なった方が安全です。
firebase.auth().onAuthStateChanged((user) => {
if (user) {
const uid = user.uid;
if (uid !== "admin_uid") {
// Force to sign out
firebase.auth().signOut();
}
} else {
// Page for non-signed in
// ...
}
});
E-Mail とパスワードによる認証の場合は、Web から登録できないようにしておけば基本的にログアウトの処理は必要ありません。
管理用のページをインターネットに公開しないのも選択肢の一つです。 管理用の PC からのみ、ブログの投稿を行える「localhost」で動作するサービスを作るのも一つの方法です。また、専用のアプリ(デスクトップアプリ)を作れば、管理用の機能はインターネット上からは利用できないのでセキュリティ上より安全になります。
まとめ
Firebase のセキュリティルールは、「人」「場所」「出来る事」が基本なので、ユーザー認証は必須のような感じがします。しかし、実際は、ブログサービスのようなアプリの場合には、「管理者」だけがユーザー認証をすれば良いので通常のサービスには実はユーザー認証は不要の場合が殆どです。
管理用の機能も、インターネットに公開しない方法、例えば「localhost」で管理機能を運用したり、デスクトップのアプリという形にすれば、インターネットからは基本的に管理機能は使えない事になるのでセキュリティ上はより安全な方法にする事が可能です。
個別のユーザー認証が必要な、メッセージサービスやストレージサービスなどの場合は、ユーザー認証機能の実装は不可欠になりますが、多くのサービスでは、「管理者」と「それ以外の一般利用者」という位置付けのサービスも多いのでユーザー認証はシンプルにできます。