보안 규칙 언어

Firebase 보안 규칙은 다양한 복잡성과 세분화 범위를 지원하는 유연하고 강력한 커스텀 언어를 활용합니다. 앱에 적합하도록 구체적이거나 일반적인 규칙을 만들 수 있습니다. 실시간 데이터베이스 규칙은 JSON 구조에서 자바스크립트와 유사한 문법을 사용합니다. Cloud Firestore 및 Cloud Storage 규칙은 CEL(Common Expression Language) 기반 언어를 사용하며, 조건부로 부여된 액세스 권한을 지원하는 matchallow 문을 사용하여 CEL에 빌드합니다.

하지만 커스텀 언어이기 때문에 사용법을 익혀야 합니다. 복잡한 규칙을 익혀 나가는 과정에서 규칙 언어를 보다 잘 이해할 수 있도록 이 가이드를 활용하시기 바랍니다.

규칙에 대해 자세히 알아보고자 하는 제품을 선택하세요.

기본 구조

Cloud Firestore

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>>
  }
}

다음 핵심 개념은 규칙을 작성할 때 반드시 숙지해야 합니다.

  • 요청: allow 문에서 호출되는 메서드이며, 실행하도록 지정할 수 있는 메서드입니다. 표준 메서드는 get, list, create, update, delete입니다. 편리한 readwrite 메서드를 통해 지정된 데이터베이스 또는 스토리지 경로에서 광범위한 읽기 및 쓰기 액세스가 가능합니다.
  • 경로: URI 경로로 표시되는 데이터베이스 또는 스토리지 위치입니다.
  • 규칙: true로 평가되면 요청을 허용하는 조건을 포함하는 allow 문입니다.

각 개념에 대해서는 아래 섹션에서 자세히 설명합니다.

Cloud Storage

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>>
  }
}

다음 핵심 개념은 규칙을 작성할 때 반드시 숙지해야 합니다.

  • 요청: allow 문에서 호출되는 메서드이며, 실행하도록 지정할 수 있는 메서드입니다. 표준 메서드는 get, list, create, update, delete입니다. 편리한 readwrite 메서드를 통해 지정된 데이터베이스 또는 스토리지 경로에서 광범위한 읽기 및 쓰기 액세스가 가능합니다.
  • 경로: URI 경로로 표시되는 데이터베이스 또는 스토리지 위치입니다.
  • 규칙: true로 평가되면 요청을 허용하는 조건을 포함하는 allow 문입니다.

각 개념에 대해서는 아래 섹션에서 자세히 설명합니다.

실시간 데이터베이스

실시간 데이터베이스에서 Firebase 보안 규칙은 JSON 문서에 포함된 자바스크립트와 유사한 표현식으로 구성됩니다.

여기에서는 다음 문법을 사용합니다.

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

규칙에는 세 가지 기본 요소가 있습니다.

  • 경로: 데이터베이스 위치입니다. 데이터베이스의 JSON 구조를 반영합니다.
  • 요청: 규칙에서 액세스를 허용하기 위해 사용하는 메서드입니다. readwrite 규칙은 광범위한 읽기 및 쓰기 액세스를 허용하지만 validate 규칙은 수신되는 데이터 또는 기존 데이터를 기반으로 액세스를 허용하는 2차 검증으로 작용합니다.
  • 조건: true로 평가되면 요청을 허용하는 조건입니다.

규칙 구성

Cloud Firestore

Cloud Firestore 및 Cloud Storage에서 규칙의 기본 요소는 다음과 같습니다.

  • service 선언: 규칙이 적용되는 Firebase 제품을 선언합니다.
  • match 블록: 규칙이 적용되는 데이터베이스 또는 스토리지 버킷의 경로를 정의합니다.
  • allow 문: 메서드별로 구분한 액세스 권한을 부여하도록 조건을 제공합니다. 지원되는 메서드는 get, list, create, update, delete이며, 편리한 메서드는 readwrite입니다.
  • 선택적 function 선언: 여러 규칙에서 사용하기 위해 조건을 결합하고 래핑할 수 있는 기능을 제공합니다.

service에는 하나 이상의 match 블록과 요청에 대한 액세스 허용 조건을 제시하는 allow 문이 포함됩니다. requestresource 변수는 규칙 조건에서 사용할 수 있습니다. Firebase 보안 규칙 언어는 function 선언도 지원합니다.

문법 버전

syntax 문은 소스를 작성하는 데 사용되는 Firebase 규칙 언어의 버전을 나타냅니다. 최신 언어 버전은 v2입니다.

rules_version = '2';
service cloud.firestore {
...
}

rules_version 문이 제공되지 않으면 규칙이 v1 엔진을 사용하여 평가됩니다.

서비스

service 선언은 규칙이 적용되는 Firebase 제품 또는 서비스를 정의합니다. 소스 파일당 하나의 service 선언만 포함할 수 있습니다.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud Storage

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Firebase CLI를 사용하여 Cloud Firestore 및 Cloud Storage 양쪽에 규칙을 정의하는 경우 별도의 파일로 규칙을 관리해야 합니다.

일치

match 블록은 요청된 작업(수신 request.path)의 경로와 일치하는 path 패턴을 선언합니다. match의 본문에는 하나 이상의 중첩된 match 블록, allow 문 또는 function 선언이 있어야 합니다. 중첩된 match 블록의 경로는 상위 match 블록의 경로를 기준으로 합니다.

path 패턴은 변수 또는 와일드 카드를 포함할 수 있는 디렉터리와 유사한 이름입니다. path 패턴은 단일 경로 세그먼트와 다중 경로 세그먼트 일치를 허용합니다. path에 바인딩된 모든 변수는 match 범위 또는 path가 선언된 모든 중첩된 범위에서 볼 수 있습니다.

path 패턴과의 일치는 부분적이거나 완전할 수 있습니다.

  • 부분 일치: path 패턴이 request.path의 프리픽스와 일치합니다.
  • 전체 일치: path 패턴이 전체 request.path와 일치합니다.

전체 일치인 경우 블록 내의 규칙이 평가됩니다. 부분 일치인 경우 중첩된 match 규칙을 테스트하여 완전히 일치하는 중첩된 path가 있는지 확인합니다.

전체 match의 규칙은 요청을 허용할지 여부를 판단하기 위해 평가됩니다. 액세스를 허용하는 일치 규칙이 있으면 요청이 허용되고, 액세스를 허용하는 일치 규칙이 없으면 요청이 거부됩니다.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

위의 예시에서와 같이 path 선언은 다음 변수를 지원합니다.

  • 단일 세그먼트 와일드 카드: 와일드 카드 변수는 중괄호로 변수를 래핑({variable})하여 경로에 선언됩니다. 이 변수는 match 문에서 string으로 액세스할 수 있습니다.
  • 재귀 와일드 카드: 재귀적 또는 다중 세그먼트 와일드 카드는 경로나 경로 아래의 다중 경로 세그먼트와 일치합니다. 이 와일드 카드는 설정한 위치 아래의 모든 경로와 일치합니다. 세그먼트 변수의 끝에 =** 문자열을 추가({variable=**})하여 이를 선언할 수 있습니다. 이 변수는 match 문에서 path 객체로 액세스할 수 있습니다.

허용

match 블록은 하나 이상의 allow 문을 포함합니다. 다음은 실제 규칙입니다. allow 규칙을 하나 이상의 메서드에 적용할 수 있습니다. Cloud Firestore 또는 Cloud Storage에 수신되는 모든 요청을 허용하려면 allow 문의 조건이 true로 평가되어야 합니다. allow read 같이 조건 없이 allow 문을 작성할 수도 있습니다. 그러나 allow 문에 조건이 포함되어 있지 않으면 메서드의 요청이 항상 허용됩니다.

메서드의 allow 규칙 중 하나라도 충족이 되면 요청이 허용됩니다. 또한 더 광범위한 규칙으로 액세스를 허용하면 규칙이 액세스를 허용하고, 액세스를 제한할 수 있는 더 세부적인 규칙은 모두 무시합니다.

다음 예시에서 모든 사용자가 자신의 파일을 읽거나 삭제할 수 있는 경우를 살펴보세요. 더 세부적인 규칙에 따라 사용자가 자신의 파일에 쓰기를 요청하고 해당 파일이 PNG인 경우에만 쓰기가 허용됩니다. 사용자는 PNG 파일이 아니더라도 하위 경로의 모든 파일을 삭제할 수 있으며, 이는 이전 규칙에서 허용했기 때문입니다.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

메서드

allow 문에는 동일한 메서드의 수신 요청에 대해 액세스를 허용하는 메서드가 포함되어 있습니다.

메서드 요청 유형
편리한 메서드
read 모든 유형의 읽기 요청
write 모든 유형의 쓰기 요청
표준 메서드
get 단일 문서 또는 파일에 대한 읽기 요청
list 쿼리 및 컬렉션에 대한 읽기 요청
create 새 문서 또는 파일 작성
update 기존 데이터베이스 문서에 쓰기 또는 파일 메타데이터 업데이트
delete 데이터 삭제

같은 match 블록의 읽기 메서드가 중첩되거나 같은 path 선언의 쓰기 메서드가 중첩되면 안 됩니다.

예를 들어 다음과 같은 규칙은 실패합니다.

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

함수

보안 규칙이 복잡해지면 조건 세트를 함수로 묶어 규칙 세트 전체에서 재사용할 수 있습니다. 보안 규칙에서는 커스텀 함수를 지원합니다. 커스텀 함수의 문법은 자바스크립트와 비슷하지만, 보안 규칙 함수는 도메인 언어로 작성되며 다음과 같은 중요한 제한사항이 있습니다.

  • 함수는 return 문 하나만 포함할 수 있습니다. 다른 로직은 포함할 수 없습니다. 예를 들어 루프를 실행하거나 외부 서비스를 호출할 수 없습니다.
  • 함수는 정의된 범위에 속하는 함수와 변수에 자동으로 액세스할 수 있습니다. 예를 들어 service cloud.firestore 범위 안에 정의된 함수는 resource 변수 및 get(), exists() 등의 기본 제공 함수에 액세스할 수 있습니다.
  • 함수는 다른 함수를 호출할 수 있지만 재귀 호출은 금지됩니다. 호출 스택 깊이는 최대 20으로 제한됩니다.
  • 규칙 버전 v2에서 함수는 let 키워드를 사용하여 변수를 정의할 수 있습니다. 함수는 최대 10개의 let 바인딩을 가질 수 있지만 반환 구문으로 끝나야 합니다.

함수는 function 키워드로 정의되며 0개 이상의 인수를 취합니다. 예를 들어 위 예시에 사용한 두 가지 유형의 조건을 하나의 함수로 결합할 수 있습니다.

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

다음은 함수 인수 및 let 할당을 보여주는 예시입니다. let 할당 문은 세미콜론으로 구분해야 합니다.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

isAdmin 할당이 관리자 컬렉션 조회를 시행하는 방법에 유의하세요. 불필요한 조회가 필요 없는 지연 평가의 경우 isAuthor가 true(&& 비교의 경우) 또는 false(|| 비교의 경우)로 표시되는 경우에만 &&(AND) 및 ||(OR) 비교의 단락 특성을 활용하여 두 번째 함수를 호출합니다.

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

보안 규칙에서 함수를 사용하면 규칙이 복잡해져도 쉽게 관리할 수 있습니다.

Cloud Storage

Cloud Firestore 및 Cloud Storage에서 규칙의 기본 요소는 다음과 같습니다.

  • service 선언: 규칙이 적용되는 Firebase 제품을 선언합니다.
  • match 블록: 규칙이 적용되는 데이터베이스 또는 스토리지 버킷의 경로를 정의합니다.
  • allow 문: 메서드별로 구분한 액세스 권한을 부여하도록 조건을 제공합니다. 지원되는 메서드는 get, list, create, update, delete이며, 편리한 메서드는 readwrite입니다.
  • 선택적 function 선언: 여러 규칙에서 사용하기 위해 조건을 결합하고 래핑할 수 있는 기능을 제공합니다.

service에는 하나 이상의 match 블록과 요청에 대한 액세스 허용 조건을 제시하는 allow 문이 포함됩니다. requestresource 변수는 규칙 조건에서 사용할 수 있습니다. Firebase 보안 규칙 언어는 function 선언도 지원합니다.

문법 버전

syntax 문은 소스를 작성하는 데 사용되는 Firebase 규칙 언어의 버전을 나타냅니다. 최신 언어 버전은 v2입니다.

rules_version = '2';
service cloud.firestore {
...
}

rules_version 문이 제공되지 않으면 규칙이 v1 엔진을 사용하여 평가됩니다.

서비스

service 선언은 규칙이 적용되는 Firebase 제품 또는 서비스를 정의합니다. 소스 파일당 하나의 service 선언만 포함할 수 있습니다.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud Storage

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Firebase CLI를 사용하여 Cloud Firestore 및 Cloud Storage 양쪽에 규칙을 정의하는 경우 별도의 파일로 규칙을 관리해야 합니다.

일치

match 블록은 요청된 작업(수신 request.path)의 경로와 일치하는 path 패턴을 선언합니다. match의 본문에는 하나 이상의 중첩된 match 블록, allow 문 또는 function 선언이 있어야 합니다. 중첩된 match 블록의 경로는 상위 match 블록의 경로를 기준으로 합니다.

path 패턴은 변수 또는 와일드 카드를 포함할 수 있는 디렉터리와 유사한 이름입니다. path 패턴은 단일 경로 세그먼트와 다중 경로 세그먼트 일치를 허용합니다. path에 바인딩된 모든 변수는 match 범위 또는 path가 선언된 모든 중첩된 범위에서 볼 수 있습니다.

path 패턴과의 일치는 부분적이거나 완전할 수 있습니다.

  • 부분 일치: path 패턴이 request.path의 프리픽스와 일치합니다.
  • 전체 일치: path 패턴이 전체 request.path와 일치합니다.

전체 일치인 경우 블록 내의 규칙이 평가됩니다. 부분 일치인 경우 중첩된 match 규칙을 테스트하여 완전히 일치하는 중첩된 path가 있는지 확인합니다.

전체 match의 규칙은 요청을 허용할지 여부를 판단하기 위해 평가됩니다. 액세스를 허용하는 일치 규칙이 있으면 요청이 허용되고, 액세스를 허용하는 일치 규칙이 없으면 요청이 거부됩니다.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

위의 예시에서와 같이 path 선언은 다음 변수를 지원합니다.

  • 단일 세그먼트 와일드 카드: 와일드 카드 변수는 중괄호로 변수를 래핑({variable})하여 경로에 선언됩니다. 이 변수는 match 문에서 string으로 액세스할 수 있습니다.
  • 재귀 와일드 카드: 재귀적 또는 다중 세그먼트 와일드 카드는 경로나 경로 아래의 다중 경로 세그먼트와 일치합니다. 이 와일드 카드는 설정한 위치 아래의 모든 경로와 일치합니다. 세그먼트 변수의 끝에 =** 문자열을 추가({variable=**})하여 이를 선언할 수 있습니다. 이 변수는 match 문에서 path 객체로 액세스할 수 있습니다.

허용

match 블록은 하나 이상의 allow 문을 포함합니다. 다음은 실제 규칙입니다. allow 규칙을 하나 이상의 메서드에 적용할 수 있습니다. Cloud Firestore 또는 Cloud Storage에 수신되는 모든 요청을 허용하려면 allow 문의 조건이 true로 평가되어야 합니다. allow read 같이 조건 없이 allow 문을 작성할 수도 있습니다. 그러나 allow 문에 조건이 포함되어 있지 않으면 메서드의 요청이 항상 허용됩니다.

메서드의 allow 규칙 중 하나라도 충족이 되면 요청이 허용됩니다. 또한 더 광범위한 규칙으로 액세스를 허용하면 규칙이 액세스를 허용하고, 액세스를 제한할 수 있는 더 세부적인 규칙은 모두 무시합니다.

다음 예시에서 모든 사용자가 자신의 파일을 읽거나 삭제할 수 있는 경우를 살펴보세요. 더 세부적인 규칙에 따라 사용자가 자신의 파일에 쓰기를 요청하고 해당 파일이 PNG인 경우에만 쓰기가 허용됩니다. 사용자는 PNG 파일이 아니더라도 하위 경로의 모든 파일을 삭제할 수 있으며, 이는 이전 규칙에서 허용했기 때문입니다.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

메서드

allow 문에는 동일한 메서드의 수신 요청에 대해 액세스를 허용하는 메서드가 포함되어 있습니다.

메서드 요청 유형
편리한 메서드
read 모든 유형의 읽기 요청
write 모든 유형의 쓰기 요청
표준 메서드
get 단일 문서 또는 파일에 대한 읽기 요청
list 쿼리 및 컬렉션에 대한 읽기 요청
create 새 문서 또는 파일 작성
update 기존 데이터베이스 문서에 쓰기 또는 파일 메타데이터 업데이트
delete 데이터 삭제

같은 match 블록의 읽기 메서드가 중첩되거나 같은 path 선언의 쓰기 메서드가 중첩되면 안 됩니다.

예를 들어 다음과 같은 규칙은 실패합니다.

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

함수

보안 규칙이 복잡해지면 조건 세트를 함수로 묶어 규칙 세트 전체에서 재사용할 수 있습니다. 보안 규칙에서는 커스텀 함수를 지원합니다. 커스텀 함수의 문법은 자바스크립트와 비슷하지만, 보안 규칙 함수는 도메인 언어로 작성되며 다음과 같은 중요한 제한사항이 있습니다.

  • 함수는 return 문 하나만 포함할 수 있습니다. 다른 로직은 포함할 수 없습니다. 예를 들어 루프를 실행하거나 외부 서비스를 호출할 수 없습니다.
  • 함수는 정의된 범위에 속하는 함수와 변수에 자동으로 액세스할 수 있습니다. 예를 들어 service cloud.firestore 범위 안에 정의된 함수는 resource 변수 및 get(), exists() 등의 기본 제공 함수에 액세스할 수 있습니다.
  • 함수는 다른 함수를 호출할 수 있지만 재귀 호출은 금지됩니다. 호출 스택 깊이는 최대 20으로 제한됩니다.
  • 규칙 버전 v2에서 함수는 let 키워드를 사용하여 변수를 정의할 수 있습니다. 함수는 최대 10개의 let 바인딩을 가질 수 있지만 반환 구문으로 끝나야 합니다.

함수는 function 키워드로 정의되며 0개 이상의 인수를 취합니다. 예를 들어 위 예시에 사용한 두 가지 유형의 조건을 하나의 함수로 결합할 수 있습니다.

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

다음은 함수 인수 및 let 할당을 보여주는 예시입니다. let 할당 문은 세미콜론으로 구분해야 합니다.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

isAdmin 할당이 관리자 컬렉션 조회를 시행하는 방법에 유의하세요. 불필요한 조회가 필요 없는 지연 평가의 경우 isAuthor가 true(&& 비교의 경우) 또는 false(|| 비교의 경우)로 표시되는 경우에만 &&(AND) 및 ||(OR) 비교의 단락 특성을 활용하여 두 번째 함수를 호출합니다.

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

보안 규칙에서 함수를 사용하면 규칙이 복잡해져도 쉽게 관리할 수 있습니다.

실시간 데이터베이스

위에서 설명한 대로 실시간 데이터베이스 규칙에는 다음과 같은 세 가지 기본 요소가 포함됩니다. 데이터베이스의 JSON 구조가 반영된 데이터베이스 위치, 요청 유형, 액세스 허용 조건입니다.

데이터베이스 위치

규칙 구조는 데이터베이스에 저장한 데이터 구조를 따라야 합니다. 예를 들어 채팅 앱의 메시지 목록에는 다음과 같은 데이터가 있을 수 있습니다.

  {
    "messages": {
      "message0": {
        "content": "Hello",
        "timestamp": 1405704370369
      },
      "message1": {
        "content": "Goodbye",
        "timestamp": 1405704395231
      },
      ...
    }
  }

규칙에서 이 구조를 반영해야 합니다. 예를 들면 다음과 같습니다.

  {
    "rules": {
      "messages": {
        "$message": {
          // only messages from the last ten minutes can be read
          ".read": "data.child('timestamp').val() > (now - 600000)",

          // new messages must have a string content and a number timestamp
          ".validate": "newData.hasChildren(['content', 'timestamp']) &&
                        newData.child('content').isString() &&
                        newData.child('timestamp').isNumber()"
        }
      }
    }
  }

위의 예시에서와 같이 실시간 데이터베이스 규칙은 경로 세그먼트를 일치시키는 $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 }
      }
    }
  }

메서드

실시간 데이터베이스에는 세 가지 유형의 규칙이 있습니다. 여기에서 두 가지 규칙 유형 readwrite는 수신되는 요청의 메서드에 적용되며, validate 규칙 유형은 데이터 구조를 적용하고 데이터의 형식과 콘텐츠를 검증합니다. .write 규칙의 액세스 허용을 확인한 후 .validate 규칙을 실행합니다.

규칙 유형
.read 사용자가 데이터를 읽을 수 있는 조건을 기술합니다.
.write 사용자가 데이터를 쓸 수 있는 조건을 기술합니다.
.validate 값의 올바른 형식, 하위 속성을 갖는지 여부, 데이터 유형을 정의합니다.

기본적으로 액세스를 허용하는 규칙이 없으면 경로의 액세스가 거부됩니다.

조건 작성

Cloud Firestore

조건이란 특정 작업을 허용할지 아니면 거부할지를 결정하는 부울 표현식입니다. requestresource 변수는 이러한 조건에 대한 컨텍스트를 제공합니다.

request 변수

request 변수에는 다음 필드와 해당하는 정보가 포함됩니다.

request.auth

Firebase 인증의 사용자 인증 정보를 포함하는 JSON 웹 토큰(JWT)입니다. auth 토큰에는 Firebase 인증을 통해 생성한 표준 클레임 세트와 모든 커스텀 클레임이 포함됩니다. Firebase 보안 규칙 및 인증을 자세히 알아보세요.

request.method

request.method는 표준 메서드 또는 커스텀 메서드일 수 있습니다. 또한 모든 읽기 전용 또는 모든 쓰기 전용 표준 메서드 각각에 적용되는 규칙의 작성을 단순화하는 데 사용할 수 있는 편리한 메서드인 readwrite도 있습니다.

request.params

request.params에는 평가에 유용할 수도 있는 request.resource와 특별히 관련되지 않은 모든 데이터가 포함됩니다. 실제로 이 매핑은 모든 표준 메서드의 경우 비어 있어야 하며, 커스텀 메서드의 경우 리소스 이외의 데이터를 포함해야 합니다. 서비스는 매개변수로 표시된 모든 키와 값의 유형을 수정하거나 이름을 바꾸지 않도록 주의해야 합니다.

request.path

request.path는 대상 resource의 경로입니다. 이 경로는 서비스를 기준으로 합니다. /와 같이 url이 아닌 안전한 문자를 포함하는 경로 세그먼트는 url로 인코딩됩니다.

resource 변수

resource는 키-값 쌍의 맵으로 표현되는 서비스 내 현재 값입니다. 조건 내에서 resource를 참조하면 서비스에서 읽은 값은 최대 하나가 됩니다. 이 조회는 리소스의 모든 서비스 관련 할당량을 계산합니다. get 요청의 경우 resource는 거부 시 할당량만 계산합니다.

연산자 및 연산자 우선순위

아래 표를 통해 Cloud Firestore 및 Cloud Storage의 규칙에서 연산자와 연산자 우선순위를 참조할 수 있습니다.

ab, 필드 f, 색인 i는 임의로 주어진 표현식입니다.

연산자 설명 결합
a[i] a() a.f 색인, 호출, 필드 액세스 왼쪽에서 오른쪽으로
!a -a 단항 부정 오른쪽에서 왼쪽으로
a/b a%b a*b 곱셈 연산자 왼쪽에서 오른쪽으로
a+b a-b 덧셈 연산자 왼쪽에서 오른쪽으로
a>b a>=b a<=b 관계 연산자 왼쪽에서 오른쪽으로
a in b 목록 또는 맵에 존재 왼쪽에서 오른쪽으로
a is type 유형 비교: type은 bool, int, float, number, string, list, map, timestamp, duration, path, latlng일 수 있습니다. 왼쪽에서 오른쪽으로
a==b a!=b 비교 연산자 왼쪽에서 오른쪽으로
a && b 조건부 AND 왼쪽에서 오른쪽으로
a || b 조건부 OR 왼쪽에서 오른쪽으로
a ? true_value : false_value 3항 표현식 왼쪽에서 오른쪽으로

Cloud Storage

조건이란 특정 작업을 허용할지 아니면 거부할지를 결정하는 부울 표현식입니다. requestresource 변수는 이러한 조건에 대한 컨텍스트를 제공합니다.

request 변수

request 변수에는 다음 필드와 해당하는 정보가 포함됩니다.

request.auth

Firebase 인증의 사용자 인증 정보를 포함하는 JSON 웹 토큰(JWT)입니다. auth 토큰에는 Firebase 인증을 통해 생성한 표준 클레임 세트와 모든 커스텀 클레임이 포함됩니다. Firebase 보안 규칙 및 인증을 자세히 알아보세요.

request.method

request.method는 표준 메서드 또는 커스텀 메서드일 수 있습니다. 또한 모든 읽기 전용 또는 모든 쓰기 전용 표준 메서드 각각에 적용되는 규칙의 작성을 단순화하는 데 사용할 수 있는 편리한 메서드인 readwrite도 있습니다.

request.params

request.params에는 평가에 유용할 수도 있는 request.resource와 특별히 관련되지 않은 모든 데이터가 포함됩니다. 실제로 이 매핑은 모든 표준 메서드의 경우 비어 있어야 하며, 커스텀 메서드의 경우 리소스 이외의 데이터를 포함해야 합니다. 서비스는 매개변수로 표시된 모든 키와 값의 유형을 수정하거나 이름을 바꾸지 않도록 주의해야 합니다.

request.path

request.path는 대상 resource의 경로입니다. 이 경로는 서비스를 기준으로 합니다. /와 같이 url이 아닌 안전한 문자를 포함하는 경로 세그먼트는 url로 인코딩됩니다.

resource 변수

resource는 키-값 쌍의 맵으로 표현되는 서비스 내 현재 값입니다. 조건 내에서 resource를 참조하면 서비스에서 읽은 값은 최대 하나가 됩니다. 이 조회는 리소스의 모든 서비스 관련 할당량을 계산합니다. get 요청의 경우 resource는 거부 시 할당량만 계산합니다.

연산자 및 연산자 우선순위

아래 표를 통해 Cloud Firestore 및 Cloud Storage의 규칙에서 연산자와 연산자 우선순위를 참조할 수 있습니다.

ab, 필드 f, 색인 i는 임의로 주어진 표현식입니다.

연산자 설명 결합
a[i] a() a.f 색인, 호출, 필드 액세스 왼쪽에서 오른쪽으로
!a -a 단항 부정 오른쪽에서 왼쪽으로
a/b a%b a*b 곱셈 연산자 왼쪽에서 오른쪽으로
a+b a-b 덧셈 연산자 왼쪽에서 오른쪽으로
a>b a>=b a<=b 관계 연산자 왼쪽에서 오른쪽으로
a in b 목록 또는 맵에 존재 왼쪽에서 오른쪽으로
a is type 유형 비교: type은 bool, int, float, number, string, list, map, timestamp, duration, path, latlng일 수 있습니다. 왼쪽에서 오른쪽으로
a==b a!=b 비교 연산자 왼쪽에서 오른쪽으로
a && b 조건부 AND 왼쪽에서 오른쪽으로
a || b 조건부 OR 왼쪽에서 오른쪽으로
a ? true_value : false_value 3항 표현식 왼쪽에서 오른쪽으로

실시간 데이터베이스

조건이란 특정 작업을 허용할지 아니면 거부할지를 결정하는 부울 표현식입니다. 다음과 같은 방법으로 실시간 데이터베이스 규칙에서 이러한 조건을 정의할 수 있습니다.

사전 정의된 변수

규칙 정의에서 몇 가지 유용한 사전 정의된 변수에 액세스할 수 있습니다. 다음은 각 변수의 간단한 요약입니다.

사전 정의된 변수
now Linux 기점을 기준으로 하는 현재 시간(밀리초)입니다. SDK의 firebase.database.ServerValue.TIMESTAMP로 생성한 타임스탬프를 검증하는 데 특히 유용합니다.
root 작업 시도 전에 Firebase 데이터베이스에 존재한 루트 경로를 나타내는 RuleDataSnapshot입니다.
newData 작업 시도 후에 존재할 데이터를 나타내는 RuleDataSnapshot입니다. 새로 기록되는 데이터와 기존 데이터를 포함합니다.
data 작업 시도 전에 존재한 데이터를 나타내는 RuleDataSnapshot입니다.
$ 변수 ID 및 동적 하위 키를 나타내는 데 사용되는 와일드카드 경로입니다.
auth 인증된 사용자의 토큰 페이로드를 나타냅니다.

규칙에서 위치에 관계없이 이러한 변수를 사용할 수 있습니다. 예를 들어 아래 보안 규칙은 /foo/ 노드에 기록되는 데이터를 100자 미만의 문자열로 제한합니다.

{
  "rules": {
    "foo": {
      // /foo is readable by the world
      ".read": true,

      // /foo is writable by the world
      ".write": true,

      // data written to /foo must be a string less than 100 characters
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

데이터 기반 규칙

데이터베이스의 모든 데이터를 규칙에 사용할 수 있습니다. 사전 정의된 변수 root, data, newData를 사용하여 쓰기 이벤트 전후에 존재하는 모든 경로에 액세스할 수 있습니다.

다음 예시에서는 /allow_writes/ 노드의 값이 true이고 상위 노드에 readOnly 플래그가 설정되지 않으며 새로 기록되는 데이터에 foo라는 하위 항목이 있을 때 쓰기 작업을 허용합니다.

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

쿼리 기반 규칙

규칙을 필터로 사용할 수는 없지만, 규칙에서 쿼리 매개변수를 사용하면 데이터 중 일부만 액세스 가능하도록 제한할 수 있습니다. 규칙에서 query. 표현식을 사용하여 쿼리 매개변수를 기준으로 읽기 또는 쓰기 액세스 권한을 부여합니다.

예를 들어 다음 쿼리 기반 규칙은 사용자 기반 보안 규칙과 쿼리 기반 규칙을 사용하여 baskets 컬렉션의 데이터 중 활성 사용자가 소유한 장바구니에만 액세스할 수 있도록 제한합니다.

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

규칙에 쿼리 매개변수가 포함된 다음 규칙은 성공합니다.

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

그러나 규칙에 매개변수가 포함되지 않은 다음 쿼리는 PermissionDenied 오류와 함께 실패합니다.

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

쿼리 기반 규칙을 사용하여 클라이언트에서 읽기 작업을 통해 다운로드할 수 있는 데이터의 양을 제한할 수도 있습니다.

예를 들어 다음 규칙은 읽기 액세스를 쿼리 결과 중 우선순위에 따라 정렬한 처음 1,000개로 제한합니다.

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

실시간 데이터베이스 보안 규칙에 다음과 같은 query. 표현식을 사용할 수 있습니다.

쿼리 기반 규칙 표현식
표현식 유형 설명
query.orderByKey
query.orderByPriority
query.orderByValue
부울 쿼리가 키, 우선순위 또는 값으로 정렬되면 true입니다. 그렇지 않으면 false입니다.
query.orderByChild 문자열
null
하위 노드를 가리키는 상대 경로를 문자열로 표현합니다. 예: query.orderByChild === "address/zip". 쿼리가 하위 노드에 따라 정렬되지 않은 경우 이 값은 null입니다.
query.startAt
query.endAt
query.equalTo
문자열
숫자
부울
null
실행 중인 쿼리의 경계를 검색합니다. 경계가 설정되지 않은 경우 null을 반환합니다.
query.limitToFirst
query.limitToLast
숫자
null
실행 중인 쿼리의 한도를 검색합니다. 한도가 설정되지 않은 경우 null을 반환합니다.

연산자

실시간 데이터베이스 규칙은 조건문에서 변수를 결합하는 데 사용할 여러 연산자를 지원합니다. 참조 문서에 있는 연산자의 전체 목록을 참조하세요.

조건 생성

실제 조건은 허용하려는 액세스에 따라 달라집니다. 규칙은 의도적으로 매우 큰 유연성을 제공하기 때문에, 결과적으로 앱의 규칙은 필요에 따라 간단하거나 복잡하게 만들 수 있습니다.

프로덕션에 즉시 사용 가능하고 간편한 규칙을 생성하는 방법을 알아보려면 기본 보안 규칙을 참조하세요.