개발여행

Firebase 보안규칙 본문

카테고리 없음

Firebase 보안규칙

jbilee 2024. 5. 6. 11:55

Image by Kris from Pixabay

 

Firebase에 앱을 호스팅한다면 원치 않는 외부인으로부터 내 앱의 데이터를 보호할 수 있도록 보안규칙을 작성하게 된다. Firebase에서는 Firestore와 Firebase Storage 각각의 서비스마다 별도로 보안규칙이 필요하다.

 

초창기에는 Firebase Storage 보안규칙에서 Firestore에 저장된 데이터를 알 방법이 없어서, Firestore 데이터베이스의 데이터를 Storage가 참조할 수 있도록 각종 방법으로 복잡한 함수들을 구현해야 했다고 한다. 하지만 2022년 업데이트 후로는 Storage에서도 Firestore 데이터베이스의 데이터를 활용해 규칙을 작성할 수 있도록 Firestore를 간편하게 참조하는 함수를 사용할 수 있게 됐다.

 

firestore.get 함수로 특정 필드값 읽기

firestore.get() 함수는 Storage에서 Firestore 데이터베이스 문서의 특정 필드값을 참조해야 할 때 쓴다. get 함수에 Firestore 문서의 주소를 인자로 전달하면 된다.

 

예시로 내 사진첩 앱은 Firestore 데이터베이스에 사진첩의 id를 문서(document)로 저장하고, 해당 id를 사진첩 썸네일 이미지의 파일명으로 Storage에 저장하도록 구조가 짜여져있다. 동일한 id를 기준으로 Firestore에 저장된 사진첩의 데이터와 Storage에 저장된 썸네일 이미지를 읽을 수 있기 때문이다.

 

유저가 Storage를 통해 사진첩의 썸네일 이미지를 변경하려면 그 사진첩의 주인(owner)로 등록돼 있어야 하는데, 사진첩의 주인인 여부는 Firestore에 ${사진첩_id}.ownerId 값으로 저장돼 있다. 주인일 경우 Storage에 write할 수 있도록 Storage 보안규칙에서 firestore.get()을 호출해 사진첩의 ownerId 값과 request를 날린 유저의 uid를 대조한다.

service firebase.storage {
  match /b/{bucket}/o {
    match /covers/{coverDocs} {
      allow read: if request.auth != null;
      allow write: if request.auth.uid == firestore.get(/databases/(default)/documents/albums/$(coverDocs)).data.ownerId;
    }
  }
}

 

규칙 시뮬레이터를 통해 firestore.get() 함수가 어떤 데이터를 리턴하는지 확인해봤다.

{
  "data": {
    "isPrivate": true
    "ownerId": "NRdJyoP5bEQ4FtldrJvi9qPlAKh2"
    "timeCreated": 1714904892713
    "cover": "https://firebasestorage.googleapis.com/v0/b/thatskyalbum.appspot.com/o/covers%2FoCrv88wUDbUvbVeHiAuV?alt=media&token=ed64d004-0086-436d-adb6-3647854f41f3"
    "name": "sample album"
    "desc": ""
  }
  "id": "oCrv88wUDbUvbVeHiAuV"
  "__name__": "/databases/%28default%29/documents/albums/oCrv88wUDbUvbVeHiAuV"
}

 

위처럼 data라는 key에 해당 문서의 필드들이 들어있기 때문에, firestore.get(...).data.${필드명} 형식으로 필드값에 접근해야 한다.

 

firestore.exists 함수로 문서 참조하기

firestore.exists() 함수에 전달한 경로에 해당하는 문서가 Firestore 데이터베이스에 존재하는지를 확인한다.

 

아래는 Firestore에 문서가 존재해야 해당 문서의 id를 가진 Storage 이미지의 read 접근을 허용하는 예시다.

service firebase.storage {
  match /b/{bucket}/o {
    match /covers/{coverDocs} {
      allow read: if firestore.exists(/databases/(default)/documents/albums/$(coverDocs))
    }
  }
}

 

firestore.get()이랑 firestore.exists() 함수를 사용할 땐 컬렉션(collection)이 아닌 문서(document)의 경로를 전달해야 한다. 반드시 `/databases` 로 시작하는 전체 경로가 들어가야 하고, 경로에 변수를 사용할 땐 $() 안에 작성한다.

 

 

참고