기본 보안 규칙

Firebase 보안 규칙을 사용하면 저장된 데이터에 대한 액세스를 제어할 수 있습니다. 유연한 규칙 구문을 사용하면 전체 데이터베이스에 대한 모든 쓰기 작업부터 특정 문서에 대한 작업까지 어떠한 상황에든 맞는 규칙을 작성할 수 있습니다.

이 가이드에서는 앱을 설정하고 데이터를 보호하는 과정에서 구현할 수 있는 몇 가지 기본적인 사용 사례를 설명합니다. 하지만 규칙 작성에 앞서 작성 언어와 보안 규칙 작동 방식에 대해 더 알아보시는 것도 좋습니다.

규칙을 보고 업데이트하려면 Firebase 보안 규칙 관리 및 배포에 설명된 단계를 따릅니다.

기본 규칙: 잠금 모드

Firebase Console에서 데이터베이스 또는 스토리지 인스턴스를 만들 때 Firebase 보안 규칙으로 데이터 액세스를 제한(잠금 모드)할 것인지 아니면 모든 사용자의 액세스를 허용(테스트 모드)할 것인지를 선택합니다. Cloud Firestore 및 실시간 데이터베이스에서 잠금 모드의 기본 규칙은 모든 사용자의 액세스를 거부합니다. Cloud Storage에서는 인증된 사용자만 스토리지 버킷에 액세스할 수 있습니다.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

실시간 데이터베이스

{
  "rules": {
    ".read": false,
    ".write": false
  }
}

Cloud Storage

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

개발 환경 규칙

앱 작업을 하는 동안 비교적 개방적이거나 제한이 없는 데이터 액세스가 필요할 수 있습니다. 프로덕션으로 앱을 배포하기 전에 규칙을 업데이트해야 합니다. 또한 앱을 배포하면 아직 출시하지 않은 앱이라도 공개적으로 액세스가 가능합니다.

Firebase는 클라이언트에게 직접적인 데이터 액세스를 허용하고 Firebase 보안 규칙은 악의적인 사용자의 액세스를 차단하는 유일한 보호 수단이라는 점에 유의하세요. 제품 로직과는 별도로 규칙을 정의하면 여러 가지 장점이 있습니다. 클라이언트가 보안 적용을 담당하지 않고, 구현 상의 버그로 인한 데이터 보안 침해가 발생하지 않으며, 무엇보다도 데이터를 보호하기 위해 중간 서버에 의존하지 않아도 됩니다.

인증된 모든 사용자

로그인한 모든 사용자가 데이터에 액세스할 수 있도록 두는 것을 권장하지 않지만 앱을 개발하는 동안 인증된 모든 사용자에게 액세스 권한을 설정하는 것은 유용할 수 있습니다.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

실시간 데이터베이스

{
  "rules": {
    ".read": "auth.uid !== null",
    ".write": "auth.uid !== null"
  }
}

Cloud Storage

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

프로덕션에 즉시 사용 가능한 규칙

앱 배포를 준비할 때 데이터가 보호되고 사용자에게 액세스 권한이 제대로 부여되는지 확인해야 합니다. 인증을 활용하여 사용자 기반 액세스를 설정하고 데이터베이스에서 직접 읽어 데이터 기반 액세스를 설정합니다.

규칙을 설정하는 방식에 따라 다른 경로에 있는 데이터에 대한 액세스를 제한하는 방법이 영향을 받기 때문에 데이터를 구조화할 때 규칙을 작성하는 것이 좋습니다.

콘텐츠 소유자 전용 액세스

이러한 규칙은 콘텐츠의 인증된 소유자로만 액세스를 제한합니다. 데이터는 한 명의 사용자만 읽고 쓸 수 있으며 데이터 경로에는 사용자의 ID가 포함됩니다.

규칙이 작동하는 경우: 이 규칙은 사용자가 데이터를 격리한 경우에 적합합니다. 즉, 데이터에 액세스해야 하는 유일한 사용자와 데이터를 만든 사용자가 같은 경우입니다.

규칙이 작동하지 않는 경우: 이 규칙 집합은 여러 사용자가 같은 데이터를 쓰거나 읽어야 할 때 작동하지 않습니다. 사용자는 데이터를 덮어쓰거나 생성한 데이터에 액세스할 수 없게 됩니다.

규칙 설정 방법: 데이터를 읽거나 쓰기 위해 액세스를 요청하는 사용자가 해당 데이터를 소유한 사용자인지 확인하는 규칙을 생성합니다.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow only authenticated content owners access
    match /some_collection/{userId}/{documents=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId
    }
  }
}

실시간 데이터베이스

{
  "rules": {
    "some_path": {
      "$uid": {
        // Allow only authenticated content owners access to their data
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid"
      }
    }
  }
}

Cloud Storage

// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/path/to/file.txt"
    match /user/{userId}/{allPaths=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

공개 및 비공개 액세스 혼합

이 규칙은 모든 사용자가 데이터 세트를 읽을 수 있지만 지정된 경로의 데이터를 생성하거나 수정하는 기능은 인증된 콘텐츠 소유자로만 제한합니다.

규칙이 작동하는 경우: 이 규칙은 요소를 공개적으로 읽을 수 있어야 하지만 수정 권한은 해당 요소의 소유자로 제한해야 하는 앱에 적합합니다. 예를 들어 채팅 앱 또는 블로그가 있습니다.

규칙이 작동하지 않는 경우: 콘텐츠 소유자 전용 규칙과 마찬가지로 여러 사용자가 같은 데이터를 수정해야 할 때 이 규칙 집합은 작동하지 않습니다. 사용자는 결국 서로의 데이터를 덮어쓰게 됩니다.

규칙 설정 방법: 모든 사용자(또는 인증된 모든 사용자)에게 읽기 액세스를 허용하고 데이터를 작성하는 사용자가 데이터 소유자인지 확인하는 규칙을 생성합니다.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow public read access, but only content owners can write
    match /some_collection/{document} {
      allow read: if true
      allow create: if request.auth.uid == request.resource.data.author_uid;
      allow update, delete: if request.auth.uid == resource.data.author_uid;
    }
  }
}

실시간 데이터베이스

{
// Allow anyone to read data, but only authenticated content owners can
// make changes to their data

  "rules": {
    "some_path": {
      "$uid": {
        ".read": true,
        // or ".read": "auth.uid !== null" for only authenticated users
        ".write": "auth.uid === $uid"
      }
    }
  }
}

Cloud Storage

service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/path/to/file.txt"
    match /user/{userId}/{allPaths=**} {
      allow read;
      allow write: if request.auth.uid == userId;
    }
  }
}

속성 기반 및 역할 기반 액세스

이러한 규칙이 작동하려면 데이터 속성을 정의하고 사용자에게 할당해야 합니다. Firebase 보안 규칙은 데이터베이스의 데이터 또는 파일의 메타데이터에 대한 요청을 확인하여 액세스를 승인하거나 거부합니다.

규칙이 작동하는 경우: 사용자에게 역할을 할당하는 경우 이 규칙을 사용하면 사용자의 역할 또는 특정 그룹을 기반으로 쉽게 액세스를 제한할 수 있습니다. 예를 들어 성적을 저장하는 경우 '학생' 그룹(콘텐츠 읽기만 가능), '선생님' 그룹(과목에 읽기 및 쓰기 가능), '교장' 그룹(모든 콘텐츠 읽기 가능)으로 서로 다른 액세스 수준을 할당할 수 있습니다.

규칙이 작동하지 않는 경우: 실시간 데이터베이스 및 Cloud Storage에서는 Cloud Firestore 규칙에 포함할 수 있는 get() 메서드를 규칙에 활용할 수 없습니다. 따라서 규칙에서 사용하는 속성을 반영하도록 데이터베이스 또는 파일 메타데이터를 구조화해야 합니다.

규칙 설정 방법: Cloud Firestore에서 읽을 수 있는 필드를 사용자 문서에 포함한 후 해당 필드를 읽고 조건부로 액세스를 허용하도록 규칙을 구성합니다. 실시간 데이터베이스에서 앱의 사용자를 정의하고 하위 노드에서 사용자에게 역할을 부여하는 데이터 경로를 생성합니다.

인증에서 커스텀 클레임을 설정한 다음 모든 Firebase 보안 규칙의 auth.token 변수에서 이 정보를 검색할 수도 있습니다.

데이터로 정의된 속성 및 역할

이러한 규칙은 Cloud Firestore 및 실시간 데이터베이스에서만 작동합니다.

Cloud Firestore

아래 규칙처럼 규칙에 읽기가 포함되어 있으면 Cloud Firestore의 읽기 작업에 대한 비용이 청구됩니다.

service cloud.firestore {
  match /databases/{database}/documents {
    // For attribute-based access control, Check a boolean `admin` attribute
    allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
    allow read: true;

    // Alterntatively, for role-based access, assign specific roles to users
    match /some_collection/{document} {
     allow read: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Reader"
     allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer"
   }
  }
}

실시간 데이터베이스

{
  "rules": {
    "some_path": {
      "${subpath}": {
        //
        ".write": "root.child('users').child(auth.uid).child('role').val() === 'admin'",
        ".read": true
      }
    }
  }
}

커스텀 클레임 속성 및 역할

이러한 규칙을 구현하려면 Firebase 인증에서 커스텀 클레임을 설정한 후 규칙에서 이 클레임을 활용합니다.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // For attribute-based access control, check for an admin claim
    allow write: if request.auth.token.admin == true;
    allow read: true;

    // Alterntatively, for role-based access, assign specific roles to users
    match /some_collection/{document} {
     allow read: if request.auth.token.reader == "true";
     allow write: if request.auth.token.writer == "true";
   }
  }
}

실시간 데이터베이스

{
  "rules": {
    "some_path": {
      "$uid": {
        // Create a custom claim for each role or group
        // you want to leverage
        ".write": "auth.uid !== null && auth.token.writer === true",
        ".read": "auth.uid !== null && auth.token.reader === true"
      }
    }
  }
}

Cloud Storage

service firebase.storage {
  // Allow reads if the group ID in your token matches the file metadata's `owner` property
  // Allow writes if the group ID is in the user's custom token
  match /files/{groupId}/{fileName} {
    allow read: if resource.metadata.owner == request.auth.token.groupId;
    allow write: if request.auth.token.groupId == groupId;
  }
}

테넌시 속성

이러한 규칙을 구현하려면 Google Cloud Identity Platform(GCIP)에서 멀티테넌시를 설정한 다음 규칙에서 테넌트를 활용합니다. 다음 예시는 특정 테넌트의 사용자 쓰기를 허용합니다(예: tenant2-m6tyz).

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // For tenant-based access control, check for a tenantID
    allow write: if request.auth.token.firebase.tenant == 'tenant2-m6tyz';
    allow read: true;
  }
}

실시간 데이터베이스

{
  "rules": {
    "some_path": {
      "$uid": {
        // Only allow reads and writes if user belongs to a specific tenant
        ".write": "auth.uid !== null && auth.token.firebase.tenant === 'tenant2-m6tyz'",
        ".read": "auth.uid !== null
      }
    }
  }
}

Cloud Storage

service firebase.storage {
  // Only allow reads and writes if user belongs to a specific tenant
  match /files/{tenantId}/{fileName} {
    allow read: if request.auth != null;
    allow write: if request.auth.token.firebase.tenant == tenantId;
  }
}