보안은 앱 개발 퍼즐에서 가장 복잡한 부분 중 하나일 수 있습니다. 대부분의 응용 프로그램에서 개발자는 인증(사용자가 누구인지) 및 권한 부여(사용자가 수행할 수 있는 작업)를 처리하는 서버를 구축하고 실행해야 합니다.
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>>
}
}
규칙을 만들 때 다음 주요 개념을 이해하는 것이 중요합니다.
- 요청:
allow
문에서 호출된 메서드입니다. 실행을 허용하는 메서드입니다. 표준 메소드는get
,list
,create
,update
및delete
입니다.read
및write
편의 메서드를 사용하면 지정된 데이터베이스 또는 스토리지 경로에 대한 광범위한 읽기 및 쓰기 액세스가 가능합니다. - 경로: URI 경로로 표시되는 데이터베이스 또는 저장소 위치입니다.
- 규칙: true로 평가되는 경우 요청을 허용하는 조건을 포함하는
allow
문입니다.
보안 규칙 버전 2
2019년 5월 현재 Firebase 보안 규칙 버전 2를 사용할 수 있습니다. 규칙 버전 2는 재귀 와일드카드 {name=**}
의 동작을 변경합니다. 컬렉션 그룹 쿼리 를 사용하려면 버전 2를 사용해야 합니다. rules_version = '2';
보안 규칙의 첫 번째 줄:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
일치하는 경로
모든 일치 문은 컬렉션이 아닌 문서를 가리켜야 합니다. match 문은 match /cities/SF
에서와 같이 특정 문서를 가리키거나 match /cities/{city}
에서와 같이 와일드카드를 사용하여 지정된 경로의 모든 문서를 가리킬 수 있습니다.
위의 예에서 일치 문은 {city}
와일드카드 구문을 사용합니다. 이는 규칙이 /cities/SF
또는 /cities/NYC
와 같은 cities
컬렉션의 모든 문서에 적용됨을 의미합니다. match 문의 allow
표현식이 평가되면 city
변수는 SF
또는 NYC
와 같은 도시 문서 이름으로 확인됩니다.
일치하는 하위 컬렉션
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에서 재귀 와일드카드는 하나 이상의 경로 항목과 일치합니다. 빈 경로와 일치하지 않으므로 match /cities/{city}/{document=**}
는 하위 컬렉션에 있는 문서와 일치하지만 city 컬렉션에는 없습니다. 반면 match /cities/{document=**}
cities
하위 컬렉션의 문서와 일치합니다. cities
컬렉션 및 하위 컬렉션.
재귀 와일드카드는 일치 문의 끝에 와야 합니다.
버전 2
보안 규칙 버전 2에서 재귀 와일드카드는 0개 이상의 경로 항목과 일치합니다. match/cities/{city}/{document=**}
는 모든 하위 컬렉션의 문서와 cities
컬렉션의 문서를 일치시킵니다.
rules_version = '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>;
}
}
}
일치 문당 최대 하나의 재귀 와일드카드를 사용할 수 있지만 버전 2에서는 이 와일드카드를 일치 문 어디에나 배치할 수 있습니다. 예를 들어:
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
문과 일치할 수 있습니다. 여러 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
임에도 불구하고 두 번째 규칙이 항상 true
이므로 cities
컬렉션에 대한 모든 읽기 및 쓰기가 허용됩니다.
보안 규칙 제한
보안 규칙으로 작업할 때 다음 제한 사항에 유의하십시오.
한계 | 세부 |
---|---|
요청당 최대 exists() , get() 및 getAfter() 호출 수 |
한도를 초과하면 권한 거부 오류가 발생합니다. 일부 문서 액세스 호출은 캐시될 수 있으며 캐시된 호출은 제한에 포함되지 않습니다. |
최대 중첩 match 문 깊이 | 10 |
중첩된 match 문 세트 내에서 허용되는 경로 세그먼트의 최대 경로 길이 | 100 |
중첩된 match 문 집합 내에서 허용되는 최대 경로 캡처 변수 수 | 20 |
최대 함수 호출 깊이 | 20 |
최대 함수 인수 수 | 7 |
함수당 let 변수 바인딩의 최대 수 | 10 |
재귀 또는 순환 함수 호출의 최대 수 | 0(허용되지 않음) |
요청당 평가되는 최대 표현식 수 | 1,000 |
규칙 세트의 최대 크기 | 규칙 세트는 두 가지 크기 제한을 준수해야 합니다.
|
클라우드 스토리지
기본 구조
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
입니다.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
개체에는 사용자의 고유 ID와 request.auth
개체의 Firebase 인증 페이로드도 포함되어 있습니다. 이에 대해서는 문서의 인증 섹션에서 자세히 설명합니다.
request
개체의 전체 속성 목록은 아래에서 확인할 수 있습니다.
속성 | 유형 | 설명 |
---|---|---|
auth | 맵<문자열, 문자열> | 사용자가 로그인하면 사용자의 고유 ID인 uid 와 Firebase 인증 JWT 클레임의 맵인 token 을 제공합니다. 그렇지 않으면 null 이 됩니다. |
params | 맵<문자열, 문자열> | 요청의 쿼리 매개변수를 포함하는 맵입니다. |
path | 길 | 요청이 수행되는 path 를 나타내는 경로입니다. |
resource | 맵<문자열, 문자열> | write 요청에만 존재하는 새 리소스 값입니다. |
time | 타임스탬프 | 요청이 평가되는 서버 시간을 나타내는 타임스탬프입니다. |
리소스 평가
규칙을 평가할 때 업로드, 다운로드, 수정 또는 삭제 중인 파일의 메타데이터를 평가할 수도 있습니다. 이를 통해 특정 콘텐츠 유형의 파일만 업로드하도록 허용하거나 특정 크기보다 큰 파일만 삭제하는 것과 같은 작업을 수행하는 복잡하고 강력한 규칙을 만들 수 있습니다.
Cloud Storage용 Firebase 보안 규칙은 Cloud Storage 객체에 표시되는 메타데이터의 키-값 쌍을 포함하는 resource
객체에 파일 메타데이터를 제공합니다. 이러한 속성은 데이터 무결성을 보장하기 위해 read
또는 write
요청 시 검사할 수 있습니다.
write
요청(예: 업로드, 메타데이터 업데이트 및 삭제)에서 요청 경로에 현재 존재하는 파일에 대한 파일 메타데이터를 포함하는 resource
개체 외에 request.resource
개체를 사용할 수도 있습니다. 여기에는 쓰기가 허용되는 경우 기록될 파일 메타데이터의 하위 집합이 포함됩니다. 이 두 값을 사용하여 데이터 무결성을 보장하거나 파일 유형 또는 크기와 같은 응용 프로그램 제약 조건을 적용할 수 있습니다.
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 | 맵<문자열, 문자열> | 개발자가 지정한 추가 사용자 정의 메타데이터의 키/값 쌍입니다. |
request.resource
에는 generation
, metageneration
, etag
, timeCreated
및 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 } } } }
실시간 데이터베이스
기본 구조
실시간 데이터베이스에서 Firebase 보안 규칙은 JSON 문서에 포함된 자바스크립트와 유사한 표현식으로 구성됩니다.
다음 구문을 사용합니다.
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
규칙에는 세 가지 기본 요소가 있습니다.
- 경로: 데이터베이스 위치입니다. 이는 데이터베이스의 JSON 구조를 미러링합니다.
- 요청: 규칙이 액세스 권한을 부여하는 데 사용하는 방법입니다.
read
및write
규칙은 광범위한 읽기 및 쓰기 액세스 권한을 부여하는 반면validate
규칙은 수신 또는 기존 데이터를 기반으로 액세스 권한을 부여하는 보조 검증 역할을 합니다. - 조건: true로 평가되는 경우 요청을 허용하는 조건입니다.
규칙이 경로에 적용되는 방식
실시간 데이터베이스에서 규칙은 원자적으로 적용됩니다. 즉, 상위 수준 상위 노드의 규칙이 보다 세분화된 하위 노드의 규칙을 재정의하고 하위 노드의 규칙이 상위 경로에 대한 액세스 권한을 부여할 수 없습니다. 상위 경로 중 하나에 대해 이미 권한을 부여한 경우 데이터베이스 구조의 더 깊은 경로에서 액세스를 구체화하거나 취소할 수 없습니다.
다음 규칙을 고려하십시오.
{ "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
이 반환되지만 rec2
는 반환되지 않는 것처럼 보일 수 있습니다. 그러나 실제 결과는 오류입니다.
자바스크립트
var db = firebase.database(); db.ref("records").once("value", function(snap) { // success method is not called }, function(err) { // error callback triggered with PERMISSION_DENIED });
목표-C
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 }];
빠른
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
을 가져오려면 직접 액세스해야 합니다.
자바스크립트
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
목표-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
빠른
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!
위치 변수
실시간 데이터베이스 규칙은 경로 세그먼트를 일치시키기 위해 $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 }
}
}
}