이 가이드는 Firebase Security Rules 언어의 핵심 문법 알아보기 가이드를 기반으로 합니다. 이 가이드에서 Cloud Storage용 Firebase Security Rules에 조건을 추가하는 방법을 알아보세요.
Cloud Storage Security Rules의 기본 구성요소는 조건입니다. 조건이란 특정 작업을 허용 또는 거부할지 여부를 결정하는 부울 표현식입니다. 기본 규칙의 경우 true
및 false
리터럴을 조건으로 사용하면 원활하게 작동합니다. 하지만 Cloud Storage용 Firebase Security Rules 언어를 사용하면 다음과 같은 작업이 가능한 좀 더 복잡한 조건을 작성할 수 있습니다.
- 사용자 인증 확인
- 수신 데이터의 유효성 검사
인증
Cloud Storage용 Firebase Security Rules는 Firebase Authentication과 통합되어 Cloud Storage에 대한 강력한 사용자 기반 인증을 제공합니다. 이렇게 하면 Firebase Authentication 토큰의 클레임에 따라 세분된 액세스 제어가 가능합니다.
인증된 사용자가 Cloud Storage에 대한 요청을 수행하면 request.auth
변수가 사용자의 uid
(request.auth.uid
) 및 Firebase Authentication JWT의 클레임(request.auth.token
)으로 채워집니다.
또한 커스텀 인증을 사용하는 경우 추가 클레임이 request.auth.token
필드에 표시됩니다.
인증되지 않은 사용자가 요청을 수행하면 request.auth
변수는 null
입니다.
이 데이터를 사용하여 인증을 통해 파일의 보안을 설정하는 일반적인 방법은 다음과 같습니다.
- 공개:
request.auth
무시 - 인증 비공개:
request.auth
가null
이 아닌지 확인 - 사용자 비공개:
request.auth.uid
가uid
경로와 같은지 확인 - 그룹 비공개: 커스텀 토큰의 클레임이 특정 클레임과 일치하는지 확인하거나 파일 메타데이터를 읽어 메타데이터 필드가 있는지 확인
공개
request.auth
컨텍스트를 고려하지 않는 모든 규칙은 사용자의 인증 컨텍스트를 고려하지 않으므로 public
규칙으로 간주될 수 있습니다.
이러한 규칙은 게임 자산, 사운드 파일 또는 기타 정적 콘텐츠와 같은 공개 데이터를 노출하는 데 유용합니다.
// Anyone to read a public image if the file is less than 100kB // Anyone can upload a public file ending in '.txt' match /public/{imageId} { allow read: if resource.size < 100 * 1024; allow write: if imageId.matches(".*\\.txt"); }
인증 비공개
애플리케이션의 특정 데이터를 인증된 사용자에게만 공개하고 비인증 사용자에게는 숨겨야 할 수 있습니다. 인증되지 않은 모든 사용자는 request.auth
변수가 null
이므로 인증을 요구하려면 request.auth
변수가 있는지 확인하면 됩니다.
// Require authentication on all internal image reads match /internal/{imageId} { allow read: if request.auth != null; }
사용자 비공개
request.auth
의 가장 일반적인 사용 사례는 프로필 사진 업로드, 개인 문서 조회와 같이 파일에 개별 사용자 단위로 권한을 부여하는 것입니다.
Cloud Storage의 파일에는 파일의 전체 '경로'가 있기 때문에 사용자가 제어하는 파일을 만들려면 규칙이 판정될 때 확인할 수 있는 고유한 사용자 식별 정보(예: 사용자의 uid
)가 파일 이름 프리픽스에 있기만 하면 됩니다.
// Only a user can upload their profile picture, but anyone can view it match /users/{userId}/profilePicture.png { allow read; allow write: if request.auth.uid == userId; }
그룹 비공개
또 다른 일반적인 사용법은 여러 팀원이 공유 문서를 공동으로 작업하는 경우와 같이 객체에 대한 그룹 권한을 허용하는 것입니다. 여기에는 몇 가지 방법이 있습니다.
- 그룹 구성원에 대한 추가 정보(예: 그룹 ID)를 포함하는 Firebase Authentication 커스텀 토큰 발급
- 파일 메타데이터에 그룹 정보(예: 그룹 ID 또는 승인된
uid
목록) 포함
이러한 데이터를 토큰이나 파일 메타데이터에 저장한 후 규칙 내에서 참조할 수 있습니다.
// 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; }
요청 검증
업로드, 다운로드, 메타데이터 변경 및 삭제는 Cloud Storage로 전송된 request
를 사용하여 검증됩니다. 위에서 설명한 request.auth
객체의 사용자 고유 ID 및 Firebase Authentication 페이로드 외에도 request
변수에는 요청이 이루어지는 파일 경로, 요청 수신 시간, 새 resource
값(쓰기 요청인 경우)이 포함됩니다.
또한 request
객체는 request.auth
객체에 사용자의 고유 ID 및 Firebase Authentication 페이로드를 포함합니다. 자세한 내용은 문서의 사용자 기반 보안 섹션을 참고하세요.
다음은 request
객체의 전체 속성 목록입니다.
속성 | 유형 | 설명 |
---|---|---|
auth |
맵<문자열, 문자열> | 사용자가 로그인하면 uid (사용자의 고유 ID) 및 token (Firebase Authentication JWT 클레임의 맵)을 제공합니다. 그렇지 않으면 null 입니다. |
params |
맵<문자열, 문자열> | 요청의 쿼리 매개변수를 포함하는 맵입니다. |
path |
경로 | 요청이 이루어지는 경로를 나타내는 path 입니다. |
resource |
맵<문자열, 문자열> | 새 리소스 값이며 write 요청에만 있습니다. |
time |
타임스탬프 | 요청을 검증하는 서버 시간을 나타내는 타임스탬프입니다. |
리소스 검증
규칙을 판정할 때 업로드, 다운로드, 수정 또는 삭제되는 파일의 메타데이터를 검증할 수도 있습니다. 이를 통해 특정 콘텐츠 유형의 파일만 업로드를 허용하거나 특정 크기보다 큰 파일만 삭제를 허용하는 등의 복잡하고 강력한 규칙을 만들 수 있습니다.
Cloud Storage용 Firebase Security Rules는 resource
객체에 파일 메타데이터를 제공하며 이 객체는 Cloud Storage 객체에 노출된 메타데이터의 키-값 쌍을 포함합니다. read
또는 write
요청에서 이러한 속성을 검사하여 데이터 무결성을 확보할 수 있습니다.
업로드, 메타데이터 업데이트, 삭제 등의 write
요청에서는 현재 요청 경로에 있는 파일의 메타데이터를 포함하는 resource
객체뿐 아니라 쓰기가 허용된 경우 쓸 파일 메타데이터 중 일부를 포함하는 request.resource
객체도 사용할 수 있습니다. 이러한 두 값을 사용하여 데이터 무결성을 확인하거나 파일 형식, 크기 등의 애플리케이션 제한사항을 적용할 수 있습니다.
다음은 resource
객체의 전체 속성 목록입니다.
속성 | 유형 | 설명 |
---|---|---|
name |
문자열 | 객체의 전체 이름입니다. |
bucket |
문자열 | 객체가 속한 버킷의 이름입니다. |
generation |
int | 이 객체의 Google Cloud Storage 객체 세대입니다. |
metageneration |
int | 이 객체의 Google Cloud Storage 객체 메타 세대입니다. |
size |
int | 객체 크기(바이트)입니다. |
timeCreated |
타임스탬프 | 객체 생성 시간을 나타내는 타임스탬프입니다. |
updated |
타임스탬프 | 객체의 마지막 업데이트 시간을 나타내는 타임스탬프입니다. |
md5Hash |
문자열 | 객체의 MD5 해시입니다. |
crc32c |
문자열 | 객체의 crc32c 해시입니다. |
etag |
문자열 | 이 객체에 연결된 etag입니다. |
contentDisposition |
문자열 | 이 객체에 연결된 콘텐츠 처리입니다. |
contentEncoding |
문자열 | 이 객체에 연결된 콘텐츠 인코딩입니다. |
contentLanguage |
문자열 | 이 객체에 연결된 콘텐츠 언어입니다. |
contentType |
문자열 | 이 객체에 연결된 콘텐츠 유형입니다. |
metadata |
맵<문자열, 문자열> | 개발자가 추가로 지정한 커스텀 메타데이터의 키-값 쌍입니다. |
request.resource
는 generation
, metageneration
, etag
, timeCreated
, updated
만 제외하고 이러한 속성을 모두 포함합니다.
Cloud Firestore로 개선
Cloud Firestore 문서에 액세스하여 다른 승인 기준을 평가할 수 있습니다.
보안 규칙에서 firestore.get()
및 firestore.exists()
함수를 사용하여 수신된 요청을 Cloud Firestore 문서와 비교할 수 있습니다.
firestore.get()
및 firestore.exists()
함수 모두 문서 경로 전체를 지정해야 합니다. 변수를 사용하여 firestore.get()
및 firestore.exists()
의 경로를 작성하는 경우 $(variable)
문법을 사용하여 변수를 명시적으로 이스케이프해야 합니다.
아래 예에는 파일에 대한 읽기 액세스를 특정 클럽의 멤버로 제한하는 규칙이 있습니다.
service firebase.storage { match /b/{bucket}/o { match /users/{club}/files/{fileId} { allow read: if club in firestore.get(/databases/(default)/documents/users/$(request.auth.id)).memberships } } }
service firebase.storage { match /b/{bucket}/o { match /users/{userId}/photos/{fileId} { allow read: if firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id)) } } }
이 Cloud Firestore 함수를 사용하는 첫 번째 Cloud Storage Security Rules를 만들고 저장하면 Firebase 콘솔 또는 Firebase CLI에 두 제품을 연결할 수 있는 권한을 사용 설정하라는 메시지가 표시됩니다.
Firebase Security Rules 관리 및 배포에 설명된 대로 IAM 역할을 삭제하여 이 기능을 사용 중지할 수 있습니다.
데이터 검증
Cloud Storage용 Firebase Security Rules는 파일 이름 및 경로 검증뿐만 아니라 contentType
및 size
와 같은 파일 메타데이터 속성 검증을 비롯한 데이터 유효성 검사에도 사용할 수 있습니다.
service firebase.storage { match /b/{bucket}/o { match /images/{imageId} { // Only allow uploads of any image file that's less than 5MB allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*'); } } }
커스텀 함수
Firebase Security Rules가 복잡해지면 조건 세트를 함수로 묶어 규칙 세트 전체에서 재사용할 수 있습니다. 보안 규칙에서는 커스텀 함수를 지원합니다. 커스텀 함수의 문법은 JavaScript와 비슷하지만, Firebase Security Rules 함수는 도메인 언어로 작성되며 다음과 같은 중요한 제한사항이 있습니다.
- 함수는
return
문 하나만 포함할 수 있습니다. 다른 로직은 포함할 수 없습니다. 예를 들어 루프를 실행하거나 외부 서비스를 호출할 수 없습니다. - 함수는 정의된 범위에 속하는 함수와 변수에 자동으로 액세스할 수 있습니다. 예를 들어
service firebase.storage
범위 안에 정의된 함수는resource
변수 및 Cloud Firestore 전용get()
,exists()
등의 기본 제공 함수에 액세스할 수 있습니다. - 함수는 다른 함수를 호출할 수 있지만 재귀 호출은 금지됩니다. 호출 스택 깊이는 최대 10으로 제한됩니다.
rules2
버전에서 함수는let
키워드를 사용하여 변수를 정의할 수 있습니다. 함수는 여러 개의 let 바인딩을 가질 수 있지만 반환 구문으로 끝나야 합니다.
함수는 function
키워드로 정의되며 0개 이상의 인수를 취합니다. 예를 들어 위 예시에 사용한 두 가지 유형의 조건을 하나의 함수로 결합할 수 있습니다.
service firebase.storage {
match /b/{bucket}/o {
// 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 /images/{imageId} {
allow read, write: if signedInOrPublic();
}
match /mp3s/{mp3Ids} {
allow read: if signedInOrPublic();
}
}
}
Firebase Security Rules에서 함수를 사용하면 복잡성이 커짐에 따라 유지관리가 더 쉬워집니다.
다음 단계
지금까지 조건에 대해 학습하며 규칙에 대해 자세히 알아봤습니다. 이제 다음과 같은 단계를 진행할 수 있습니다.
핵심 사용 사례를 처리하는 방법을 알아보고 규칙 개발, 테스트, 배포를 위한 워크플로를 살펴봅니다.
- 일반적인 시나리오를 다루는 규칙을 작성합니다.
- 안전하지 않은 규칙을 찾아 피해야 할 상황을 검토하며 지식을 쌓습니다.
- Cloud Storage 에뮬레이터 및 전용 보안 규칙 테스트 라이브러리를 사용하여 규칙을 테스트합니다.
- Rules 배포에 사용할 수 있는 방법을 검토합니다.