Firebase Summit で発表されたすべての情報をご覧ください。Firebase を使用してアプリ開発を加速し、自信を持ってアプリを実行する方法を紹介しています。詳細

セキュリティルールの仕組み

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

セキュリティは、アプリ開発パズルの最も複雑なピースの 1 つです。ほとんどのアプリケーションでは、開発者は、認証 (ユーザーが誰であるか) と承認 (ユーザーができること) を処理するサーバーを構築して実行する必要があります。

Firebase セキュリティ ルールは、中間 (サーバー) レイヤーを削除し、データに直接接続するクライアントに対してパスベースのアクセス許可を指定できるようにします。このガイドを使用して、着信リクエストにルールが適用される方法について詳しく学んでください。

製品を選択して、そのルールの詳細を確認してください。

クラウド ファイアストア

基本構造

Cloud Firestore と Cloud Storage の Firebase セキュリティ ルールは、次の構造と構文を使用します。

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

ルールを構築する際には、次の重要な概念を理解することが重要です。

  • Request: allowステートメントで呼び出されるメソッド。これらは実行を許可するメソッドです。標準メソッドは、 getlistcreateupdate 、およびdeleteです。 readおよびwriteの便利なメソッドにより、指定されたデータベースまたはストレージ パスに対する広範な読み取りおよび書き込みアクセスが可能になります。
  • パス: URI パスとして表されるデータベースまたはストレージの場所。
  • ルール:要求が true と評価された場合に要求を許可する条件を含むallowステートメント。

セキュリティ ルール バージョン 2

2019 年 5 月の時点で、Firebase セキュリティ ルールのバージョン 2 が利用可能になりました。ルールのバージョン 2 では、再帰ワイルドカード{name=**}の動作が変更されています。コレクション グループ クエリを使用する場合は、バージョン 2 を使用する必要があります。 rules_version = '2';を作成して、バージョン 2 にオプトインする必要があります。セキュリティ ルールの最初の行:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

一致するパス

すべての match ステートメントは、コレクションではなく、ドキュメントを指す必要があります。 match ステートメントは、 match /cities/SFのように特定のドキュメントを指すか、またはmatch /cities/{city}のようにワイルドカードを使用して指定されたパス内の任意のドキュメントを指すことができます。

上記の例では、match ステートメントで{city}ワイルドカード構文を使用しています。これは、規則が/cities/SF/cities/NYCなどのcitiesコレクション内のすべてのドキュメントに適用されることを意味します。 match ステートメントのallow式が評価されると、 city変数はSFNYCなどの都市ドキュメント名に解決されます。

一致するサブコレクション

Cloud Firestore のデータはドキュメントのコレクションに編成され、各ドキュメントはサブコレクションを通じて階層を拡張できます。セキュリティ ルールが階層データとどのように相互作用するかを理解することが重要です。

citiesコレクションの各ドキュメントにlandmarksサブコレクションが含まれている状況を考えてみましょう。セキュリティ ルールは一致したパスにのみ適用されるため、 citiesコレクションで定義されたアクセス制御はlandmarksサブコレクションには適用されません。代わりに、サブコレクションへのアクセスを制御する明示的なルールを記述します。

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

      // Explicitly define rules for the 'landmarks' subcollection
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}

matchステートメントをネストする場合、内側のmatchステートメントのパスは常に、外側のmatchステートメントのパスに対して相対的です。したがって、次のルールセットは同等です。

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

再帰ワイルドカード

ルールを任意の深い階層に適用する場合は、再帰ワイルドカード構文{name=**}を使用します。

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

再帰的なワイルドカード構文を使用すると、ドキュメントが深くネストされたサブコレクションにある場合でも、ワイルドカード変数には一致するパス セグメント全体が含まれます。たとえば、上記のルールは/cities/SF/landmarks/coit_towerにあるドキュメントに一致し、 document変数の値はSF/landmarks/coit_towerになります。

ただし、再帰ワイルドカードの動作はルールのバージョンに依存することに注意してください。

バージョン 1

セキュリティ ルールは、デフォルトでバージョン 1 を使用します。バージョン 1 では、再帰ワイルドカードは 1 つ以上のパス項目に一致します。空のパスには一致しないため、 match /cities/{city}/{document=**}はサブコレクション内のドキュメントに一致しますが、 citiesコレクション内のドキュメントには一致しません。一方、 match /cities/{document=**}はサブコレクション内の両方のドキュメントに一致しますcitiesコレクションとサブコレクション。

再帰ワイルドカードは、match ステートメントの最後にある必要があります。

バージョン 2

バージョン 2 のセキュリティ ルールでは、再帰ワイルドカードは 0 個以上のパス項目に一致します。 match/cities/{city}/{document=**}は、すべてのサブコレクション内のドキュメントと、 citiesコレクション内のドキュメントに一致します。

rules_version = '2';を追加して、バージョン 2 にオプトインする必要があります。あなたのセキュリティルールの一番上に:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

match ステートメントごとに再帰ワイルドカードを最大 1 つ使用できますが、バージョン 2 では、このワイルドカードを match ステートメントの任意の場所に配置できます。例えば:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

コレクション グループ クエリを使用する場合は、バージョン 2 を使用する必要があります。コレクション グループ クエリの保護を参照してください。

match ステートメントの重複

ドキュメントが複数のmatchステートメントに一致する可能性があります。複数のallow式がリクエストに一致する場合、いずれかの条件がtrueであればアクセスが許可されます。

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

上記の例では、最初のルールは常にfalseですが、2 番目のルールは常にtrueであるため、 citiesコレクションに対するすべての読み取りと書き込みが許可されます。

セキュリティ ルールの制限

セキュリティ ルールを操作するときは、次の制限に注意してください。

リミット詳細
リクエストあたりのexists()get() 、およびgetAfter()呼び出しの最大数
  • 単一ドキュメント リクエストとクエリ リクエストの場合は 10。
  • 複数ドキュメントの読み取り、トランザクション、およびバッチ書き込みの場合は 20。以前の制限である 10 も、各操作に適用されます。

    たとえば、3 つの書き込み操作を含むバッチ書き込み要求を作成し、セキュリティ ルールで 2 つのドキュメント アクセス呼び出しを使用して各書き込みを検証するとします。この場合、各書き込みは 10 回のアクセス呼び出しのうち 2 回を使用し、バッチ化された書き込み要求は 20 回のアクセス呼び出しのうち 6 回を使用します。

いずれかの制限を超えると、許可拒否エラーが発生します。

一部のドキュメント アクセス呼び出しはキャッシュされる可能性があり、キャッシュされた呼び出しは制限に対してカウントされません。

ネストされたmatchステートメントの最大深さ10
ネストされたmatchステートメントのセット内で許可される、パス セグメント内の最大パス長100
ネストされたmatchステートメントのセット内で許可されるパス キャプチャ変数の最大数20
関数呼び出しの最大深度20
関数の引数の最大数7
関数あたりのlet変数バインディングの最大数10
再帰的または循環的な関数呼び出しの最大数0 (許可されていません)
リクエストごとに評価される式の最大数1,000
ルールセットの最大サイズルールセットは、次の 2 つのサイズ制限に従う必要があります。
  • Firebase コンソールまたはfirebase deployを使用して CLI から発行されるルールセット テキスト ソースのサイズに対する 256 KB の制限。
  • Firebase がソースを処理し、バックエンドでアクティブにしたときに生じる、コンパイル済みルールセットのサイズに対する 250 KB の制限。

クラウドストレージ

基本構造

Cloud Firestore と Cloud Storage の Firebase セキュリティ ルールは、次の構造と構文を使用します。

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

ルールを構築する際には、次の重要な概念を理解することが重要です。

  • Request: allowステートメントで呼び出されるメソッド。これらは実行を許可するメソッドです。標準メソッドは、 getlistcreateupdate 、およびdeleteです。 readおよびwriteの便利なメソッドにより、指定されたデータベースまたはストレージ パスに対する広範な読み取りおよび書き込みアクセスが可能になります。
  • パス: URI パスとして表されるデータベースまたはストレージの場所。
  • ルール:要求が true と評価された場合に要求を許可する条件を含むallowステートメント。

一致するパス

Cloud Storage セキュリティ ルールは、Cloud Storage 内のファイルへのアクセスに使用されるファイル パスmatchします。ルールは正確なパスまたはワイルドカード パスにmatchさせることができ、ルールをネストすることもできます。リクエスト メソッドを許可する一致ルールがない場合、または条件がfalseと評価される場合、リクエストは拒否されます。

完全一致

// Exact match for "images/profilePhoto.png"
match /images/profilePhoto.png {
  allow write: if <condition>;
}

// Exact match for "images/croppedProfilePhoto.png"
match /images/croppedProfilePhoto.png {
  allow write: if <other_condition>;
}

ネストされた一致

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/profilePhoto.png"
  match /profilePhoto.png {
    allow write: if <condition>;
  }

  // Exact match for "images/croppedProfilePhoto.png"
  match /croppedProfilePhoto.png {
    allow write: if <other_condition>;
  }
}

ワイルドカードの一致

ルールを使用して、ワイルドカードを使用してパターンをmatchさせることもできます。ワイルドカードは、 profilePhoto.pngなどの単一の文字列、またはimages/profilePhoto.pngなどの複数のパス セグメントを表す名前付き変数です。

{string}のように、ワイルドカード名を中かっこで囲んでワイルドカードを作成します。 {path=**}のように、ワイルドカード名に=**を追加することで、複数セグメントのワイルドカードを宣言できます。

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/*"
  // e.g. images/profilePhoto.png is matched
  match /{imageId} {
    // This rule only matches a single path segment (*)
    // imageId is a string that contains the specific segment matched
    allow read: if <condition>;
  }

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

複数のルールがファイルに一致する場合、結果はすべてのルール評価の結果のORになります。つまり、ファイルが一致するいずれかのルールがtrueと評価された場合、結果はtrueになります。

上記のルールでは、ファイル "images/profilePhoto.png" はconditionまたはother_conditionが true と評価された場合に読み取ることができますが、ファイル "images/users/user:12345/profilePhoto.png" はother_conditionの結果のみの対象となります。 .

ワイルドカード変数は、ファイル名またはパスの承認を提供するmatch内から参照できます。

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

Cloud Storage セキュリティ ルールはカスケードしません。ルールは、リクエスト パスが指定されたルールのパスと一致する場合にのみ評価されます。

評価を依頼する

アップロード、ダウンロード、メタデータの変更、削除は、Cloud Storage に送信されたrequestを使用して評価されます。 request変数には、要求が実行されているファイル パス、要求が受信された時刻、および要求が書き込みの場合は新しいresource値が含まれます。 HTTP ヘッダーと認証状態も含まれます。

requestオブジェクトには、 request.authオブジェクトにユーザーの一意の ID と Firebase Authentication ペイロードも含まれています。これについては、ドキュメントの認証セクションで詳しく説明します。

requestオブジェクトのプロパティの完全なリストは、以下で入手できます。

財産タイプ説明
auth map<文字列, 文字列>ユーザーがログインすると、ユーザーの一意の ID であるuidと Firebase Authentication JWT クレームのマップであるtokenが提供されます。それ以外の場合はnullになります。
params map<文字列, 文字列>リクエストのクエリ パラメータを含むマップ。
pathリクエストが実行されているpath表すパス。
resource map<文字列, 文字列> writeリクエストのみに存在する新しいリソース値。
timeタイムスタンプリクエストが評価されるサーバー時間を表すタイムスタンプ。

リソース評価

ルールを評価するときに、アップロード、ダウンロード、変更、または削除されるファイルのメタデータを評価することもできます。これにより、特定のコンテンツ タイプのファイルのみをアップロードしたり、特定のサイズを超えるファイルのみを削除したりするなどの複雑で強力なルールを作成できます。

Cloud Storage の Firebase セキュリティ ルールは、 resourceオブジェクトでファイル メタデータを提供します。これには、Cloud Storage オブジェクトで表示されるメタデータのキーと値のペアが含まれます。これらのプロパティは、 readまたはwrite要求で検査して、データの整合性を確保できます。

writeリクエスト (アップロード、メタデータの更新、削除など) では、リクエスト パスに現在存在するファイルのファイル メタデータを含むresourceオブジェクトに加えて、 request.resourceオブジェクトを使用することもできます。これには、書き込みが許可されている場合に書き込まれるファイル メタデータのサブセットが含まれます。これら 2 つの値を使用して、データの整合性を確保したり、ファイルの種類やサイズなどのアプリケーションの制約を適用したりできます。

resourceオブジェクトのプロパティの完全なリストを以下に示します。

財産タイプ説明
nameストリングオブジェクトの完全な名前
bucketストリングこのオブジェクトが存在するバケットの名前。
generation整数このオブジェクトのGoogle Cloud Storage オブジェクトの世代
metageneration整数このオブジェクトのGoogle Cloud Storage オブジェクトのメタ世代。
size整数オブジェクトのサイズ (バイト単位)。
timeCreatedタイムスタンプオブジェクトが作成された時刻を表すタイムスタンプ。
updatedタイムスタンプオブジェクトが最後に更新された時刻を表すタイムスタンプ。
md5Hashストリングオブジェクトの MD5 ハッシュ。
crc32cストリングオブジェクトの crc32c ハッシュ。
etagストリングこのオブジェクトに関連付けられた etag。
contentDispositionストリングこのオブジェクトに関連付けられたコンテンツの配置。
contentEncodingストリングこのオブジェクトに関連付けられたコンテンツ エンコーディング。
contentLanguageストリングこのオブジェクトに関連付けられたコンテンツの言語。
contentTypeストリングこのオブジェクトに関連付けられたコンテンツ タイプ。
metadata map<文字列, 文字列>開発者が指定した追加のカスタム メタデータのキーと値のペア。

request.resourceには、 generationmetagenerationetagtimeCreated 、およびupdatedを除いて、これらすべてが含まれています。

セキュリティ ルールの制限

セキュリティ ルールを操作するときは、次の制限に注意してください。

リミット詳細
リクエストごとのfirestore.exists()およびfirestore.get()呼び出しの最大数

単一ドキュメント リクエストとクエリ リクエストの場合は 2。

この制限を超えると、許可拒否エラーが発生します。

同じドキュメントへのアクセス呼び出しはキャッシュされる場合があり、キャッシュされた呼び出しは制限に対してカウントされません。

完全な例

すべてをまとめると、イメージ ストレージ ソリューションのルールの完全な例を作成できます。

service firebase.storage {
 match /b/{bucket}/o {
   match /images {
     // Cascade read to any image type at any path
     match /{allImages=**} {
       allow read;
     }

     // Allow write files to the path "images/*", subject to the constraints:
     // 1) File is less than 5MB
     // 2) Content type is an image
     // 3) Uploaded content type matches existing content type
     // 4) File name (stored in imageId wildcard variable) is less than 32 characters
     match /{imageId} {
       allow write: if request.resource.size < 5 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && request.resource.contentType == resource.contentType
                    && imageId.size() < 32
     }
   }
 }
}

リアルタイム データベース

基本構造

Realtime Database では、Firebase セキュリティ ルールは、JSON ドキュメントに含まれる JavaScript に似た式で構成されます。

次の構文を使用します。

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

ルールには 3 つの基本要素があります。

  • パス:データベースの場所。これは、データベースの JSON 構造を反映しています。
  • リクエスト:これらは、ルールがアクセスを許可するために使用するメソッドです。 readおよびwriteルールは幅広い読み取りおよび書き込みアクセスを許可しますが、 validateルールは受信データまたは既存のデータに基づいてアクセスを許可するための二次検証として機能します。
  • 条件: true と評価された場合にリクエストを許可する条件。

パスへのルールの適用方法

Realtime Database では、ルールはアトミックに適用されます。つまり、上位レベルの親ノードのルールは、より詳細な子ノードのルールをオーバーライドし、より深いノードのルールは親パスへのアクセスを許可できません。親パスの 1 つに対してアクセス権を既に付与している場合、データベース構造のより深いパスでアクセス権を絞り込んだり取り消したりすることはできません。

次のルールを考慮してください。

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          // ignored, since read was allowed already
          ".read": false
        }
     }
  }
}

このセキュリティ構造により、 /foo/に値がtrueの子bazが含まれている場合はいつでも/bar/を読み取ることができます。 /foo/bar/の下の".read": falseルールは、子パスによってアクセスを取り消すことができないため、ここでは効果がありません。

直観的にはわからないかもしれませんが、これはルール言語の強力な部分であり、最小限の労力で非常に複雑なアクセス権限を実装できます。これは、ユーザーベースのセキュリティに特に役立ちます。

ただし、 .validateルールはカスケードしません。書き込みを許可するには、すべての検証ルールが階層のすべてのレベルで満たされている必要があります。

さらに、ルールは親パスには適用されないため、要求された場所またはアクセスを許可する親の場所にルールがない場合、読み取りまたは書き込み操作は失敗します。影響を受けるすべての子パスにアクセスできる場合でも、親の場所での読み取りは完全に失敗します。次の構造を検討してください。

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

ルールがアトミックに評価されることを理解していないと、 /records/パスを取得すると rec1 は返されるがrec1は返されないように思えるかもしれませrec2 。ただし、実際の結果はエラーです。

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
注:この Firebase 製品は、App Clip ターゲットでは使用できません。
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
迅速
注:この Firebase 製品は、App Clip ターゲットでは使用できません。
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
ジャワ
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
休み
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

/records/での読み取り操作はアトミックであり、 /records/の下のすべてのデータへのアクセスを許可する読み取りルールがないため、 PERMISSION_DENIEDエラーがスローされます。 Firebase コンソールのセキュリティ シミュレーターでこのルールを評価すると、読み取り操作が拒否されたことがわかります。

Attempt to read /records with auth=Success(null)
    /
    /records

No .read rule allowed the operation.
Read was denied.

/records/パスへのアクセスを許可する読み取りルールがないため、操作は拒否されましたが、リクエストしたパスにないため、 rec1のルールは評価されなかったことに注意してください。 rec1を取得するには、直接アクセスする必要があります。

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
注:この Firebase 製品は、App Clip ターゲットでは使用できません。
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
迅速
注:この Firebase 製品は、App Clip ターゲットでは使用できません。
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
ジャワ
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
休み
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

ロケーション変数

Realtime Database ルールは、パス セグメントに一致する$location変数をサポートしています。パス セグメントの前に$プレフィックスを使用して、ルールをパスに沿った子ノードに一致させます。

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

$variableを定数パス名と並行して使用することもできます。

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }