Firebase 실시간 데이터베이스 보안 규칙 이해

Firebase 실시간 데이터베이스 보안 규칙은 데이터베이스에 대한 읽기 및 쓰기 권한이 있는 사용자, 데이터의 구조 및 색인 생성 여부를 결정합니다. 이 규칙은 Firebase 서버에 상주하며 항상 자동으로 적용됩니다. 모든 읽기 및 쓰기 요청은 규칙에 따라 허용될 때만 완료됩니다. 기본적으로 이 규칙은 데이터베이스에 대한 접근을 일체 차단합니다. 이는 규칙을 맞춤설정하거나 인증을 설정하기 전까지 데이터베이스가 악용되지 않도록 보호하기 위한 조치입니다.

실시간 데이터베이스 보안 규칙은 자바스크립트와 유사한 문법을 사용하며 다음과 같은 4가지 유형이 있습니다.

규칙 유형
.read 사용자가 데이터를 읽을 수 있는 조건을 기술합니다.
.write 사용자가 데이터를 쓸 수 있는 조건을 기술합니다.
.validate 값의 올바른 형식, 하위 속성을 갖는지 여부 및 데이터 유형을 정의합니다.
.indexOn 정렬 및 쿼리를 위해 색인을 생성할 하위 항목을 지정합니다.

Realtime Database 보안 개요

Firebase Realtime Database는 앱의 보안을 관리하는 데 필요한 모든 도구를 제공합니다. 이러한 도구를 사용하면 사용자를 쉽게 인증하고 사용자 권한을 적용하며 입력을 검증할 수 있습니다.

Firebase 기반 앱은 다른 기술 스택에 비해 클라이언트 측 코드를 더 많이 실행합니다. 따라서 보안에 대한 접근법도 지금까지 익숙했던 방식과는 조금 다를 수 있습니다.

인증

앱 보안의 첫 단계는 일반적으로 사용자 식별이며 이 프로세스를 인증이라고 합니다. Firebase 인증을 사용하여 사용자가 앱에 로그인하도록 할 수 있습니다. Firebase 인증에는 이메일과 비밀번호 로그인, 익명 로그인 등을 비롯하여 Google 및 Facebook과 같은 일반적인 인증 방법에 대한 삽입형 지원이 포함됩니다.

사용자의 ID는 중요한 보안 개념입니다. 사용자마다 다른 데이터를 보유하며, 사용자의 권한도 서로 다를 수 있습니다. 예를 들어 채팅 애플리케이션에서 각 메시지는 메시지를 작성한 사용자에 연결됩니다. 또한 사용자는 자신의 메시지를 삭제할 수 있지만 다른 사용자가 게시한 메시지는 삭제할 수 없습니다.

승인

사용자 식별은 보안의 일부에 불과합니다. 사용자가 누구인지 알아냈으면 데이터베이스에 있는 데이터에 대한 액세스를 제어할 방법이 필요합니다. 실시간 데이터베이스 보안 규칙으로 각 사용자의 액세스를 제어할 수 있습니다. 예를 들어 다음은 /foo/ 경로를 누구나 읽을 수 있지만 아무도 쓸 수 없도록 하는 보안 규칙입니다.

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

.read.write 규칙은 하위로 전파되므로 이 규칙 세트는 /foo/ 경로의 모든 데이터와 /foo/bar/baz와 같은 더 깊은 경로에 대한 읽기 액세스 권한을 부여합니다. 데이터베이스에서 상위의 .read.write 규칙이 하위 규칙을 재정의하므로 /foo/bar/baz 경로의 규칙이 false로 평가되더라도 이 예시에서는 /foo/bar/baz에 대한 읽기 액세스 권한이 부여됩니다.

실시간 데이터베이스 보안 규칙에는 기본 제공 변수 및 함수가 포함되어 있으므로 다른 경로, 서버 측 타임스탬프, 인증 정보 등을 참조할 수 있습니다. 다음은 인증된 사용자에게 /users/<uid>/에 대한 쓰기 권한을 부여하는 규칙의 예시입니다. 여기에서 <uid>는 Firebase Authentication을 통해 가져온 사용자 ID입니다.

{
  "rules": {
    "users": {
      "$uid": {
        ".write": "$uid === auth.uid"
      }
    }
  }
}

데이터 검증

Firebase Realtime Database에는 스키마가 없습니다. 따라서 개발 중에 손쉽게 구조를 변경할 수 있지만, 앱을 배포할 준비가 끝난 후에는 데이터의 일관성을 유지해야 합니다. 규칙 언어에는 .read.write 규칙과 동일한 표현식을 사용하여 검증 로직을 적용할 수 있는 .validate 규칙이 포함됩니다. 유일한 차이점은 검증 규칙은 하위로 전파되지 않는다는 것입니다. 따라서 모든 관련 검증 규칙이 true로 판정되어야 쓰기가 허용됩니다.

이러한 규칙은 /foo/에 기록되는 데이터를 100자 미만(영문 기준)의 문자열로 제한합니다.

{
  "rules": {
    "foo": {
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

검증 규칙은 .read.write 규칙과 동일한 기본 제공 함수 및 변수에 모두 액세스할 수 있습니다. 이러한 함수와 변수를 사용하여 데이터베이스의 다른 위치에 있는 데이터, 사용자 ID, 서버 시간 등을 인식하는 검증 규칙을 만들 수 있습니다.

데이터베이스 색인 정의

Firebase Realtime Database는 데이터 정렬 및 쿼리를 지원합니다. 데이터 크기가 작은 경우 데이터베이스는 임시 쿼리를 지원하므로 개발 중에는 일반적으로 색인이 필요하지 않습니다. 그러나 앱의 규모가 커져도 쿼리가 계속 정상적으로 작동하도록 하려면 앱을 출시하기 전에 색인을 지정해야 합니다.

색인은 .indexOn 규칙을 사용하여 지정합니다. 다음은 공룡 목록의 키 및 길이 필드를 색인화하는 색인 선언의 예시입니다.

{
  "rules": {
    "dinosaurs": {
      ".indexOn": ["height", "length"]
    }
  }
}

다음 단계