다단계 인증 구성

이 페이지에서는 이메일이나 SMS로 인증 코드를 전송하여 사용자의 신원을 확인할 수 있는 다단계 인증(MFA)을 구성하는 방법을 설명합니다. 이 기능을 사용하면 계정과 연결된 이메일 주소나 전화번호를 소유하고 있는지 확인할 수 있습니다. MFA는 사용자 인증 정보 반복 입력 공격 및 계정 탈취(ATO)로부터 사용자를 보호하는 데 도움이 될 수 있습니다.

MFA는 점수 기반 사이트 키에 사용할 수 있으며 체크박스 사이트 키에는 사용할 수 없습니다.

MFA의 구성 프로세스 이해

reCAPTCHA Enterprise의 MFA는 일반 reCAPTCHA Enterprise 워크플로를 기반으로 작동합니다. 대략적으로 MFA 워크플로는 다음과 같습니다.

  1. 클라이언트에서 중요 워크플로를 계측합니다.
  2. 클라이언트의 execute() 호출에서 반환한 토큰을 사용하여 평가를 만듭니다. 평가를 만들 때 MFA 매개변수를 포함하여 MFA requestToken을 가져옵니다.
  3. 사용하려는 채널(SMS 또는 이메일)에 따라 requestToken을 사용하여 MFA 챌린지를 트리거합니다.
  4. 웹 또는 모바일 앱에서 최종 사용자가 입력한 PIN을 확인합니다.
  5. 확인 요청에 반환된 토큰을 사용하여 새 평가를 요청합니다.

시작하기 전에

  1. 환경에서 reCAPTCHA Enterprise를 설정하는 가장 좋은 방법을 선택하고 설정을 완료합니다.

  2. 보안 검토 후 MFA에 액세스할 수 있습니다. 이 기능에 사이트를 온보딩하려면 Google 영업팀에 문의하세요. 영업팀에 다음과 같은 온보딩 정보를 제공합니다.

    • Google Cloud 프로젝트 번호
    • 온보딩할 사이트 키
    • 평균 QPS(초당 이메일/SMS 수)
    • 최대 QPS(초당 이메일/SMS 수)
    • 이메일 MFA의 경우 발신자 주소 및 테스트 중 필요한 이메일 주소 또는 도메인
    • SMS MFA의 경우 대상 국가(사용자 국가)별 최대 및 평균 QPS
  3. 플랫폼별 안내에 따라 MFA를 사용 설정할 플랫폼에 reCAPTCHA Enterprise를 통합합니다.

클라이언트에서 중요 워크플로 계측

위험 평가를 위해 execute() 함수를 사용하여 reCAPTCHA Enterprise에 필요한 정보를 전달합니다. execute() 함수는 토큰 생성 시 확인된 프라미스를 반환합니다.

웹사이트

다음 샘플 코드에서와 같이 twofactor 매개변수를 execute() 함수에 추가합니다.

grecaptcha.enterprise.execute(SITE_KEY, {
  action: 'login',
  twofactor: true
}).then(token => {
  // Handle the generated token.
});

Android

Android 애플리케이션용 토큰 생성 안내를 따릅니다. 추가 매개변수는 필요하지 않습니다.

iOS

iOS 애플리케이션용 토큰 생성 안내를 따릅니다. 추가 매개변수는 필요하지 않습니다.

평가 요청

execute() 함수에서 생성된 토큰으로 백엔드에서 reCAPTCHA Enterprise 클라이언트 라이브러리 또는 Google Cloud CLI를 사용하여 인증을 위한 평가 요청을 수행합니다. 평가를 요청하는 방법은 평가 작성을 참조하세요.

이메일 주소 및 전화번호와 같은 해싱된 계정 식별자와 엔드포인트를 한 개 이상 제공하여 평가를 확인합니다. 해싱된 계정 식별자는 웹사이트에 고유한 사용자 계정의 영구적인 익명 식별자입니다. 안정적인 계정 식별자의 단방향 해시를 사용합니다. Google과 공유하지 않는 안정적인 보안 비밀이 포함된 sha256-hmac를 사용하는 것이 좋습니다.

{
  "event": {
    "token": "token",
    "siteKey": "key",
    "hashedAccountId": "BP3ptt00D9W7UMzFmsPdEjNH3Chpi8bo40R6YW2b"
  },
  "accountVerification": {
    "endpoints": [{
      "emailAddress": "foo@bar.com",
    },
    {
      "phoneNumber": "+11111111111",
    }]
  }
}

기능과의 통합이 성공하면 다음 예시와 같이 MFA와 관련된 추가 정보가 평가에 포함되어야 합니다.

{
  [...],
  "accountVerification": {
    "endpoints": [{
      "emailAddress": "foo@bar.com",
      "requestToken": "tplIUFvvJUIpLaOH0hIVj2H71t5Z9mDK2RhB1SAGSIUOgOIsBv",
      "lastVerificationTime": "",
    },
    {
      "phoneNumber": "+11111111111",
      "requestToken": "fwdgk0kcg1W0mbpetYlgTZKyrp4IHKzjgRkb6vLNZeBQhWdR3a",
      "lastVerificationTime": "",
    }],
    "latestVerificationResult": "RESULT_UNSPECIFIED"
  }
}

평가에는 토큰을 발행한 기기에서 지정된 엔드포인트에 대한 최근의 성공적인 확인 날짜 및 시간이 포함됩니다(있는 경우). 또한 암호화된 문자열이 포함된 엔드포인트당 requestToken 필드 하나도 포함됩니다. 엔드포인트에 MFA 도전과제를 트리거하려면 암호화된 문자열을 클라이언트에 다시 보내야 합니다. 요청 토큰은 15분 동안 유효합니다.

MFA 관련 정보 외에도 평가 응답에는 계정 방어자와 관련된 정보가 포함됩니다. recommended_action 필드에서는 MFA 챌린지를 트리거하기 전에 취할 수 있는 조치를 보여줍니다.

다음 예시는 MFA 건너뛰기를 권장 작업으로 표시하는 샘플 평가를 보여줍니다.

{
  [...],
  "accountDefenderAssessment": {
    labels: ["PROFILE_MATCH"],
    "recommended_action": "SKIP_2FA"
  }
}

recommended actions 필드에는 다음 값이 포함될 수 있습니다.

설명
RECOMMENDED_ACTION_UNSPECIFIED 계정 방어자가 이 요청을 판단할 수 없음을 나타냅니다.
SKIP_2FA 계정 방어자가 이 평가에서 MFA를 건너뛰는 것이 안전하다고 간주함을 나타냅니다. 일반적으로 사용자가 최근 이 기기에서 사이트에 인증했음을 의미합니다.
REQUEST_2FA 사용자에 대한 MFA 챌린지를 트리거함을 나타냅니다. 자세한 내용은 계정 방어자 평가 응답을 참조하세요.

클라이언트에서 MFA 챌린지 트리거

평가에 포함된 정보를 기반으로 사용자에게 챌린지를 트리거하기로 결정한 경우 평가에서 확인하려는 엔드포인트의 MFA 요청 토큰을 클라이언트로 다시 보냅니다. 이 요청 토큰은 MFA 챌린지를 트리거하는 데 필요합니다.

challengeAccount() 호출을 통해 MFA 챌린지를 트리거합니다. challengeAccount() 함수는 챌린지가 완료되면 해결되거나 오류 또는 제한 시간 초과 시 거부되는 프라미스를 리턴합니다. 완료되면 업데이트된 정보가 포함된 새 토큰이 생성된 후 평가를 위해 전송됩니다.

MFA 통합 테스트

MFA 통합을 빠르게 테스트하려면 다음 값을 제공하여 challengeAccount()를 호출하여 MFA 챌린지를 트리거할 수 있습니다.

  • REQUEST_TOKEN_FROM_ASSESSMENT: 평가 응답의 requestToken 필드 값입니다.
  • CONTAINER_HTML_COMPONENT_ID: 확인 챌린지를 렌더링해야 하는 HTML 구성요소의 ID입니다. 이 매개변수를 지정하지 않으면 챌린지는 페이지 상단의 오버레이에 렌더링됩니다.

다음 예시에서는 'challengeAccount()'를 호출하여 MFA 챌린지를 트리거하는 방법을 보여줍니다.

grecaptcha.enterprise.challengeAccount(SITE_KEY, {
  'account-token': REQUEST_TOKEN_FROM_ASSESSMENT,
  'container': CONTAINER_HTML_COMPONENT_ID
}).then(newToken => {
  // Handle the new token.
});

challengeAccount() 요청이 성공하면 수신된 핀을 입력할 수 있는 HTML 구성요소가 표시됩니다. 올바른 핀을 입력하면 newToken 변수가 백엔드에서 생성된 평가를 통해 확인할 결과 토큰이 포함된 연결 함수로 전달됩니다.

웹사이트

다음 매개변수를 사용하여 확인 핸들을 만들고 챌린지를 시작합니다.

// Initialize verification handle.
const verificationHandle = grecaptcha.enterprise.eap.initTwoFactorVerificationHandle(
  SITE_KEY,
  REQUEST_TOKEN_FROM_ASSESSMENT
);

// Call the challenge API.
verificationHandle.challengeAccount().then(
  (challengeResponse) => {
    if (challengeResponse.isSuccess()) {
      // Handle success: Usually this means displaying an input for the user to
      // enter the pin that they received and then call the `verifyAccount(pin)`
      // method described below.
    } else {
      // Handle API failure
    }
  });

Android

앱에서 ContextchallengeAccount() 호출을 통해 MFA 챌린지를 트리거합니다.

Recaptcha.getClient(this)
   .challengeAccount(recaptchaHandle, requestToken)
   .addOnSuccessListener(
       this,
       new OnSuccessListener<VerificationHandle>() {
         @Override
         public void onSuccess(VerificationHandle handle) {
           VerificationHandle verificationHandle = handle;
           // Handle success ...
         }
       })
   .addOnFailureListener(
       this,
       new OnFailureListener() {
         @Override
         public void onFailure(@NonNull Exception e) {
           if (e instanceof ApiException) {
              ApiException apiException = (ApiException) e;
              Status apiErrorStatus = apiException.getStatusCode();
              // Handle API errors ...
           } else {
              // Handle other failures ...
           }

         }
       });

iOS

challengeAccount() 호출을 통해 MFA 챌린지를 트리거합니다.

recaptchaClient.challengeAccount(withRequestToken: "Request Token").then { verificationHandler in
  // Show your UI and retrieve the pin from the user.
}.catch { error in
  // Handle error.
}

클라이언트에서 MFA 코드 확인

최종 사용자로부터 PIN을 가져온 후에는 핀이 올바른지 여부를 검증해야 합니다.

웹사이트

최종 사용자가 입력한 PIN으로 verificationHandle.verifyAccount()를 호출하여 PIN이 올바른지 확인합니다.

verificationHandle.verifyAccount(pin).then(
  (verifyResponse) => {
    if (verifyResponse.isSuccess()) {
      // Handle success: Send the result of `verifyResponse.getVerdictToken()`
      // to the backend in order to determine if the code was valid.
    } else {
      // Handle API failure
    }
  },
  (error) => {
    // Handle other errors
  }
);

Android

앱의 Activity에서 verifyAccount()을 호출하여 입력한 PIN이 올바른지 확인합니다.

Recaptcha.getClient(this)
   .verifyAccount("userProvidedPIN", recaptchaHandle)
   .addOnSuccessListener(
       this,
       new OnSuccessListener<VerificationResult>() {
         @Override
         public void onSuccess(VerificationResult result) {
           if (result.getVerificationStatus().isSuccess()) {
             String recaptchaToken = result.recaptchaToken().orNull()
             // Handle success ...
           } else {
             VerificationHandle verificationHandle =
                              result.verificationHandle().orNull();
             Status errorStatus = result.getVerificationStatus();
             // Handle retries ...
           }
         }
       })
   .addOnFailureListener(
       this,
       new OnFailureListener() {
         @Override
         public void onFailure(@NonNull Exception e) {
           if (e instanceof ApiException) {
              ApiException apiException = (ApiException) e;
              Status apiErrorStatus = apiException.getStatusCode();
              // Handle API errors ...
           } else {
              // Handle other failures ...
           }
         }
       });

iOS

verificationHandler 객체의 verifyPin() 메서드를 호출하여 확인을 완료합니다.

handler.verifyPin("PIN") { recaptchaToken, recaptchaError in
  // Handle token/error.
}

새 평가 요청

해싱된 계정 식별자 및 endpoints 필드를 사용하여 새 평가를 요청합니다.

클라이언트에서 워크플로가 완료되면 트리거한 인증 결과를 가져올 때 사용할 수 있는 새 토큰을 받게 됩니다. 평가에는 성공한 최근의 성공 인증과 관련된 최신 타임스탬프와 성공 결과 상태가 포함되어야 합니다.

다음 예시는 클라이언트에서 가져온 새 토큰을 사용하여 새 평가를 요청하면 받는 샘플 평가를 보여줍니다.

{
  [...],
  "accountVerification": {
    "endpoints": [{
      "emailAddress": "foo@bar.com",
      "requestToken": "tplIUFvvJUIpLaOH0hIVj2H71t5Z9mDK2RhB1SAGSIUOgOIsBv",
      "lastVerificationTime": "2020-03-23 08:27:12 PST",
    }],
    "latestVerificationResult": "SUCCESS_USER_VERIFIED"
  }
}

latestVerificationResult 필드는 다음 표에 나열된 것과 다른 상태를 표시할 수 있습니다.

인증 결과 상태 설명
SUCCESS_USER_VERIFIED 사용자가 성공적으로 인증되었습니다.
ERROR_USER_NOT_VERIFIED 사용자가 인증 챌린지에 답하지 못했습니다.
ERROR_SITE_ONBOARDING_INCOMPLETE 사이트가 이 기능을 사용할 수 있도록 올바르게 온보딩되지 않았습니다.
ERROR_RECIPIENT_NOT_ALLOWED 이 수신자에게는 테스트 중 SMS 및 이메일 전송이 승인되지 않았습니다.
ERROR_RECIPIENT_ABUSE_LIMIT_EXHAUSTED 이 수신자는 짧은 기간 내에 이미 인증 코드를 너무 많이 받았습니다.
ERROR_CUSTOMER_QUOTA_EXHAUSTED 사용 가능한 MFA 할당량을 초과했습니다.
ERROR_CRITICAL_INTERNAL 시스템 내부 오류로 인해 인증을 완료할 수 없습니다.
RESULT_UNSPECIFIED 최근 인증에 대한 정보가 없습니다(인증 내역 없음).