이메일 열거 보호 사용 설정 또는 중지

이 가이드에서는 이메일 열거 보호 기능을 설명하고 사용 설정 및 중지하는 방법을 보여줍니다. 2023년 9월 15일 이후에 프로젝트를 만든 경우 이메일 열거 보호가 기본적으로 사용 설정됩니다.

개요

이메일 열거는 악의적인 행위자가 API에 이메일 주소를 전달하고 응답을 확인하여 시스템의 사용자를 추측하거나 확인하는 무차별 대입 공격의 한 유형입니다.

이메일 열거 보호가 없으면 Identity Platform에서 이메일 열거 공격에 사용할 수 있는 정보를 반환합니다.

  • 시스템에 존재하지 않는 이메일 주소로 로그인을 시도합니다. Identity Platform에서 EMAIL_NOT_FOUND 오류를 반환합니다.

  • 시스템에 이미 존재하는 이메일 주소로 가입을 시도합니다. Identity Platform에서 EMAIL_EXISTS 오류를 반환합니다.

Identity Platform의 이메일 열거 보호 기능을 사용하여 이러한 공격으로부터 앱의 사용자 계정을 보호할 수 있습니다.

이메일 열거 보호가 사용 설정되면 프로젝트에서 다음 동작을 수행합니다.

  • fetchSignInForEmail API는 실패합니다. 익명으로 인증된 사용자를 이메일 주소와 연결하는 것도 Android의 SDK 버전 22.3.0 이전, iOS의 10.18.0 이전, 웹의 10.6.0 이전 버전에서는 작동하지 않습니다.

  • 모든 플랫폼에서 createAuthUri REST API 또는fetchSignInMethodsForEmail 클라이언트 SDK 메서드를 호출할 때 지정된 이메일 주소의 로그인 메서드 목록이 더 이상 반환되지 않습니다.

  • 사용자는 먼저 새 주소를 확인하지 않으면 이메일 주소를 변경할 수 없습니다. 예를 들어 더 이상 모든 플랫폼에서 update REST API, setAccountInfo REST API 또는 updateEmail 클라이언트 SDK 메서드로 사용자의 이메일 주소를 변경할 수 없습니다.

    웹 및 Android의 경우 verifyBeforeUpdateEmail, iOS의 경우 sendEmailVerification(beforeUpdatingEmail:)을 대신 사용할 수 있습니다.

  • 더 이상 setAccountInfo REST API를 사용하여 이메일/비밀번호 제공업체를 기존 사용자 계정에 연결할 수 없습니다. 모든 플랫폼에서 더 이상 EmailAuthCredential과 함께 linkWithCredential 클라이언트 SDK 메서드를 사용할 수 없습니다. 대신 REST API signUp을 사용하여 idToken 필드에 사용자의 ID 토큰을 전달하고 연결할 email, password 필드를 전달합니다.

  • 요청 유형이 VERIFY_AND_CHANGE_EMAIL 또는 PASSWORD_RESETsendOobCode REST API를 호출하여 시작되고 모든 플랫폼에서 웹 및 Android의 경우 verifyBeforeUpdateEmail, iOS의 경우 sendEmailVerification(beforeUpdatingEmail:) 또는 sendPasswordResetEmail클라이언트 SDK 메서드를 호출할 때와 같은 이메일 확인 흐름의 오류 응답을 삭제합니다.

    비밀번호 재설정 요청을 보내면 이메일 주소가 있는 경우에만 확인 메일이 전송됩니다. 이메일 주소 변경 요청을 보내면 이메일 주소가 아직 없는 경우에만 확인 메일이 전송됩니다. 두 경우 모두 이메일이 전송되지 않은 경우를 나타내는 특정 오류 메시지가 없습니다.

    사용자가 이메일 인증 흐름 없이 가입하는 것을 허용하지 않는 것이 좋습니다.

  • 잘못된 로그인 케이스는 INVALID_LOGIN_CREDENTIALS 오류 응답을 반환합니다. 유효하지 않은 가입 사례에서는 계속 EMAIL_EXISTS 오류를 반환합니다. 다음 섹션의 권장사항을 참조하세요.

앱에서 이메일 열거 보호에 의해 변경된 동작을 사용하는 경우 현재 중지할 수 있습니다. 그러나 장기적으로는 권장하지 않습니다. 다음 섹션을 참조하세요.

보안 권장사항

계정 탈취 공격을 수행하는 가장 일반적인 방법 중 하나는 유출되거나 추측하기 쉬운 사용자 인증 정보를 사용하여 크리덴셜 스터핑 공격을 수행하는 것입니다. 이메일 열거는 사용자에 대한 민감한 정보를 가져오거나 사용자에 대한 피싱 공격을 수행하는 데 사용될 수 있습니다. 이러한 이유로 이메일 열거 보호 기능을 사용하여 이러한 공격으로부터 앱을 보호하는 것이 좋습니다.

  • 2023년 9월 15일 이후에 프로젝트를 만든 경우 이메일 열거 보호가 기본적으로 사용 설정됩니다. 이메일 열거 보호를 사용 설정한 상태로 두고 이 가이드의 앞부분에서 설명한 동작을 사용하지 않는 것이 좋습니다.

  • 2023년 9월 15일 이전에 프로젝트를 만든 경우 이메일 열거 보호가 자동으로 사용 설정되지 않습니다.

    앱에서 이 가이드의 앞부분에서 설명한 동작을 사용하지 않는 경우 이메일 열거 보호를 즉시 사용 설정하는 것이 좋습니다.

    앱이 앞에서 설명한 동작을 사용하는 경우 가능한 한 빨리 마이그레이션을 시작하고 이메일 열거 보호를 사용 설정하는 것이 좋습니다.

이메일 열거 보호를 사용하는 것 외에도 EMAIL_EXISTS 오류를 계속 반환하는 프로젝트의 가입 엔드포인트 악용이 방지되도록 조치를 취하는 것이 좋습니다. 이렇게 하는 방법은 다음과 같습니다.

  • 앱 체크를 사용 설정합니다.
  • reCAPTCHA를 가입 흐름에 통합합니다.
  • 이메일 주소와 비밀번호 또는 이메일 링크를 사용한 로그인을 허용하지 않고 대신 Google 로그인과 같은 다른 방법을 사용합니다.

이메일 열거 보호 사용 설정

이메일 열거 보호를 사용 설정하려면 다음 단계를 따르세요.

Firebase Console

  1. Firebase Console에서 Firebase 인증 설정 페이지로 이동합니다.

    Firebase 인증 설정으로 이동

    1. 탐색창에서 사용자 작업을 선택합니다.

    2. 이메일 열거 보호(권장)를 선택합니다.

  2. 저장을 클릭합니다.

Node.js

  1. Admin SDK를 설치합니다.

  2. 이메일 열거 보호를 사용 설정하려면 다음 중 하나를 사용합니다.

    • 프로젝트 수준에서 보호하려면 다음 안내를 따르세요.

      import { getAuth } from 'firebase-admin/auth';
      
      getAuth().projectConfigManager().updateProjectConfig(
        {
          emailPrivacyConfig: {
            enableImprovedEmailPrivacy: true,
          },
        }
      );
      
    • 테넌트 수준에서 보호하려면 다음 안내를 따르세요.

      import { getAuth } from 'firebase-admin/auth';
      
      getAuth().tenantConfigManager().updateTenant(TENANT_ID,
        {
          emailPrivacyConfig: {
            enableImprovedEmailPrivacy: true,
          },
        }
      );
      

      TENANT_ID를 이메일 열거 보호를 사용 설정할 테넌트 ID로 바꿉니다.

REST

  1. Google Cloud 콘솔에서 gcloud auth print-access-token 명령어를 사용하여 프로젝트 ID의 액세스 토큰을 출력합니다.

    gcloud auth print-access-token --project=PROJECT_ID
    
  2. Identity Toolkit API를 사용하여 프로젝트 ID에 이메일 열거 보호를 사용 설정합니다.

    curl -X PATCH -d "{'emailPrivacyConfig':{'enableImprovedEmailPrivacy':true}}" \
        -H 'Authorization: Bearer ACCESS_TOKEN' \
        -H 'Content-Type: application/json' -H 'X-Goog-User-Project: PROJECT_ID' \
        "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=emailPrivacyConfig"
    

다음을 바꿉니다.

  • ACCESS_TOKEN: 이전에 생성한 액세스 토큰입니다.
  • PROJECT_ID: 프로젝트 ID입니다.

이메일 열거 보호 중지

이메일 열거 보호를 중지하려면 다음 단계를 따르세요.

Firebase Console

  1. Firebase Console에서 Firebase 인증 설정 페이지로 이동합니다.

    Firebase 인증 설정으로 이동

    1. 탐색창에서 사용자 작업을 선택합니다.

    2. 이메일 열거 보호(권장)를 선택 해제합니다.

  2. 저장을 클릭합니다.

Node.js

  1. Admin SDK를 설치합니다.

  2. 이메일 열거 보호를 사용 중지하려면 다음 중 하나를 사용합니다.

    • 프로젝트 수준에서 보호하려면 다음 안내를 따르세요.

      import { getAuth } from 'firebase-admin/auth';
      
      getAuth().projectConfigManager().updateProjectConfig(
        {
          emailPrivacyConfig: {
            enableImprovedEmailPrivacy: false,
          },
        }
      );
      
    • 테넌트 수준에서 보호하려면 다음 안내를 따르세요.

      import { getAuth } from 'firebase-admin/auth';
      
      getAuth().tenantConfigManager().updateTenant(TENANT_ID,
        {
          emailPrivacyConfig: {
            enableImprovedEmailPrivacy: false,
          },
        }
      );
      

      TENANT_ID를 이메일 열거 보호를 사용 중지하려는 테넌트 ID로 바꿉니다.

REST

  1. Google Cloud 콘솔에서 gcloud auth print-access-token 명령어를 사용하여 프로젝트 ID의 액세스 토큰을 출력합니다.

    gcloud auth print-access-token --project=PROJECT_ID
    
  2. Identity Toolkit API를 사용하여 이메일 열거 보호를 중지합니다.

    curl -X PATCH -d "{'emailPrivacyConfig':{'enableImprovedEmailPrivacy':false}}" \
        -H 'Authorization: Bearer ACCESS_TOKEN' \
        -H 'Content-Type: application/json' -H 'X-Goog-User-Project: PROJECT_ID' \
        "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=emailPrivacyConfig"
    

다음을 바꿉니다.

  • ACCESS_TOKEN: 이전에 생성한 액세스 토큰입니다.
  • PROJECT_ID: 프로젝트 ID입니다.

오류 응답 예시

사용자가 잘못된 이메일 주소 또는 비밀번호로 로그인을 시도하거나 시스템에 이미 존재하는 이메일 주소로 가입하려고 하면 Identity Platform이 다음과 비슷한 오류를 반환합니다.

{
"code": "auth/internal-error",
"message": "{\"error\":{\"code\":400,\"message\":\"INVALID_LOGIN_CREDENTIALS\",\"errors\":[{\"message\":\"INVALID_LOGIN_CREDENTIALS\",\"domain\":\"global\",\"reason\":\"invalid\"}]}}"
}