SMS OTP 양식 권장사항

SMS를 전송하여 사용자에게 일회용 비밀번호(OTP)를 제공하도록 요청하여 신원을 확인하는 것이 일반적입니다. SMS OTP의 사용 사례는 다음과 같습니다.

  • 2단계 인증 사용자 이름과 비밀번호 외에도 SMS OTP는 계정이 SMS OTP를 수신한 사람의 소유라는 강력한 신호로 사용될 수 있습니다.
  • 전화번호 인증 일부 서비스에서는 전화번호를 사용자의 기본 식별자로 사용합니다. 이러한 서비스에서 사용자는 전화번호와 SMS로 수신한 OTP를 입력하여 본인 인증을 할 수 있습니다. PIN과 결합하여 2단계 인증을 구성하는 경우도 있습니다.
  • 계정 복구 사용자가 계정에 액세스할 수 없게 되면 계정을 복구할 방법이 필요합니다. 등록된 이메일 주소로 이메일을 보내거나 전화번호로 SMS OTP를 보내는 것이 일반적인 계정 복구 방법입니다.
  • 결제 확인 결제 시스템에서 일부 은행 또는 신용카드 발급기관은 보안상의 이유로 결제자에게 추가 인증을 요청합니다. 이러한 목적으로 SMS OTP가 일반적으로 사용됩니다.

이러한 사용 사례에 맞는 SMS OTP 양식을 빌드하는 권장사항을 계속 읽어보세요.

체크리스트

SMS OTP를 사용하여 최상의 사용자 환경을 제공하려면 다음 단계를 따르세요.

  • 다음과 함께 <input> 요소를 사용합니다.
    • type="text"
    • inputmode="numeric"
    • autocomplete="one-time-code"
  • @BOUND_DOMAIN #OTP_CODE을 OTP SMS 메시지의 마지막 줄로 사용합니다.
  • WebOTP API를 사용합니다.

<input> 요소 사용

<input> 요소가 있는 양식을 사용하는 것은 모든 브라우저에서 작동하므로 따를 수 있는 가장 중요한 권장사항입니다. 이 게시물의 다른 추천이 일부 브라우저에서 작동하지 않더라도 사용자는 여전히 OTP를 수동으로 입력하고 제출할 수 있습니다.

<form action="/verify-otp" method="POST">
  <input type="text"
      inputmode="numeric"
      autocomplete="one-time-code"
      pattern="\d{6}"
      required>
</form>

다음은 입력란이 브라우저 기능을 최대한 활용할 수 있도록 하는 몇 가지 아이디어입니다.

type="text"

OTP는 일반적으로 5자리 또는 6자리 숫자이므로 입력란에 type="number"을 사용하면 모바일 키보드가 숫자로만 변경되므로 직관적으로 보일 수 있습니다. 브라우저는 입력 필드가 여러 숫자의 시퀀스가 아닌 셀 수 있는 숫자일 것으로 예상하므로 이는 권장되지 않으며, 이로 인해 예기치 않은 동작이 발생할 수 있습니다. type="number"를 사용하면 입력란 옆에 위쪽 및 아래쪽 버튼이 표시됩니다. 이 버튼을 누르면 숫자가 증가하거나 감소하며 앞에 있는 0이 삭제될 수 있습니다.

대신 type="text"를 사용하세요. 이렇게 해도 모바일 키보드가 숫자로만 바뀌지는 않지만, inputmode="numeric" 사용에 관한 다음 도움말에서 이 작업을 수행하므로 괜찮습니다.

inputmode="numeric"

inputmode="numeric"를 사용하여 모바일 키보드를 숫자 전용으로 변경합니다.

일부 웹사이트에서는 OTP 입력란에 type="tel"를 사용합니다. 포커스가 맞춰지면 모바일 키보드가 숫자 전용(* 및 # 포함)으로 전환되기 때문입니다. 이 방법은 과거에 inputmode="numeric"가 널리 지원되지 않았을 때 사용되었습니다. Firefox에서 inputmode="numeric"를 지원하기 시작했으므로 의미론적으로 잘못된 type="tel" 핵을 사용할 필요가 없습니다.

autocomplete="one-time-code"

autocomplete 속성을 사용하면 개발자가 브라우저에 자동 완성 지원을 제공할 권한을 지정하고 브라우저에 필드에 필요한 정보 유형을 알릴 수 있습니다.

autocomplete="one-time-code"를 사용하면 양식이 열려 있는 동안 사용자가 SMS 메시지를 받을 때마다 운영체제가 SMS의 OTP를 휴리스틱 방식으로 파싱하고 키보드가 사용자가 입력할 OTP를 추천합니다. iOS, iPadOS, macOS의 Safari 12 이상에서만 작동하지만, 이러한 플랫폼에서 SMS OTP 환경을 개선하는 더 나은 방법이므로 사용하는 것이 좋습니다.

autocomplete="one-time-code"님의 생생한 모습

autocomplete="one-time-code"는 사용자 환경을 개선하지만 SMS 메시지가 출처 바인딩 메시지 형식을 준수하도록 더 많은 작업을 할 수 있습니다.

선택사항 속성

선택 속성은 다음과 같습니다.

  • pattern는 입력된 OTP가 일치해야 하는 형식을 지정합니다. 정규 표현식을 사용하여 일치 패턴을 지정합니다. 예를 들어 \d{6}은 OTP를 6자리 문자열로 제한합니다. pattern에 대한 자세한 내용은 더 복잡한 실시간 유효성 검사에 JavaScript 사용을 참조하세요.
  • required는 사용자가 입력란을 작성해야 함을 나타냅니다.

자세한 내용은 로그인 양식 권장사항을 참고하세요.

SMS 텍스트 형식 지정

SMS로 전송되는 출처 바인딩 일회용 코드 사양에 맞춰 OTP를 입력하는 사용자 환경을 개선합니다.

기본적으로 형식 규칙은 다음과 같습니다. SMS 메시지를 수신자 도메인(앞에 @가 붙음)과 OTP(앞에 #가 붙음)로 끝냅니다.

예를 들면 다음과 같습니다.

Your OTP is 123456

@web-otp.example.com #123456

OTP 메시지의 표준 형식을 사용하면 더 쉽고 안정적으로 추출할 수 있습니다. OTP 코드를 웹사이트와 연결하면 사용자를 속여 악성 사이트에 코드를 제공하도록 유도하기가 더 어려워집니다.

정확한 서식 규칙

정확한 규칙은 다음과 같습니다.

  • 메시지는 하나 이상의 숫자가 포함된 4~10자의 영숫자 문자열이 포함된 인간이 읽을 수 있는 텍스트(선택사항)로 시작하며, 마지막 줄은 URL과 OTP를 위해 남겨둡니다.
  • API를 호출한 웹사이트 URL의 도메인 부분 앞에 @가 있어야 합니다.
  • URL에는 #가 포함되어야 하며 그 뒤에 OTP가 와야 합니다. 문자 수는 140자(영문 기준) 이하여야 합니다.

이 형식을 사용하면 다음과 같은 이점이 있습니다.

  • OTP는 도메인에 바인딩됩니다. 사용자가 SMS 메시지에 지정된 도메인 이외의 도메인에 있는 경우 OTP 추천이 표시되지 않습니다. 또한 피싱 공격 및 잠재적인 계정 도용의 위험을 완화합니다.
  • 이제 브라우저는 알 수 없고 불안정한 휴리스틱에 의존하지 않고도 OTP를 안정적으로 추출할 수 있습니다.

웹사이트에서 autocomplete="one-time-code"를 사용하는 경우 iOS 14 이상이 설치된 Safari는 다음 규칙에 따라 OTP를 추천합니다.

이 SMS 메시지 형식은 Safari 이외의 브라우저에도 도움이 됩니다. Android의 Chrome, Opera, Vivaldi도 WebOTP API를 통해 출처 바인딩 일회성 코드 규칙을 지원하지만 autocomplete="one-time-code"를 통해서는 지원하지 않습니다.

WebOTP API 사용

WebOTP API는 SMS 메시지로 수신된 OTP에 대한 액세스를 제공합니다. transport에 sms가 포함된 otp 유형(OTPCredential)으로 navigator.credentials.get()를 호출하면 웹사이트는 출처 기반 일회용 코드를 준수하는 SMS가 전송되고 사용자가 액세스 권한을 부여할 때까지 기다립니다. OTP가 자바스크립트에 전달되면 웹사이트는 양식에서 OTP를 사용하거나 서버에 직접 POST할 수 있습니다.

navigator.credentials.get({
  otp: {transport:['sms']}
})
.then(otp => input.value = otp.code);
WebOTP API의 작동 모습

WebOTP API를 사용하여 웹에서 전화번호 인증에서 WebOTP API를 사용하는 방법을 자세히 알아보거나 다음 스니펫을 복사하여 붙여넣으세요. <form>에서 action 및 method 속성을 설정해야 합니다.

// Feature detection
if ('OTPCredential' in window) {
  window.addEventListener('DOMContentLoaded', e => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;
    // Cancel the WebOTP API if the form is submitted manually.
    const ac = new AbortController();
    const form = input.closest('form');
    if (form) {
      form.addEventListener('submit', e => {
        // Cancel the WebOTP API.
        ac.abort();
      });
    }
    // Invoke the WebOTP API
    navigator.credentials.get({
      otp: { transport:['sms'] },
      signal: ac.signal
    }).then(otp => {
      input.value = otp.code;
      // Automatically submit the form when an OTP is obtained.
      if (form) form.submit();
    }).catch(err => {
      console.log(err);
    });
  });
}