클라이언트가 서비스에 등록을 요청하게 되면, 사실 서버는 챌린지이외에도 몇 가지 정보들을 함께 클라이언트에게 응답해줍니다.


Credential Creation Options

등록 프로세스는 요청을 받은 RP서버가 클라이언트에게 전달할 몇 가지 정보들을 생성하는 것으로 시작됩니다.

몇 가지 정보들은 인증장치에서 credentialRP서버의 요구에 맞게 생성하기 위한 정보로 사용됩니다.

응답 정보 예시

const publicKeyCredentialCreationOptions = {
  challenge: Uint8Array.from(
          randomStringFromServer, c => c.charCodeAt(0)),
  rp: {
    name: "Duo Security",
    id: "duosecurity.com",
  },
  user: {
    id: Uint8Array.from(
            "UZSL85T9AFC", c => c.charCodeAt(0)),
    name: "lee@webauthn.guide",
    displayName: "Lee",
  },
  pubKeyCredParams: [{alg: -7, type: "public-key"}],
  authenticatorSelection: {
    authenticatorAttachment: "cross-platform",
  },
  timeout: 60000,
  attestation: "direct"
};

네, 뭔가 많습니다. 왠지 어지럽습니다.

어지러움을 해소하기 위해 오늘은 지난 포스트에서 다룬 챌린지를 제외한 정보들에 대해 차근차근 알아가 보겠습니다.

rp (required)

rp: {
    name: "Duo Security"
    id: "duosecurity.com"
  }

rp(Relying Party)는 인증 서버가 아닌 사용자가 로그인 하고자 하는 서비스의 서버를 의미합니다.

name에는 특별한 제약사항이 없지만, id의 경우 반드시 도메인명과 같거나, 도메인명의 부분집한을 사용해야 합니다.

예를 들어 RP서버의 origin이 https://login.example.com:1337 이라면

login.example.com 혹은 example.comrpId로 사용할 수 있습니다.

n.example.com 혹은 comrpId로 사용 할 수 없습니다.

user (required)

user: {
    id: Uint8Array.from(
        "UZSL85T9AFC", c => c.charCodeAt(0)),
    name: "lee@webauthn.guide",
    displayName: "Lee"
    }

user는 인증 등록을 요청한 사용자정보를 나타냅니다. 특히 id는 인증장치가 credential private key와 함께 저장하는 값이기 때문에, 사용자를 특정지을 수 없는 값을 사용하는것이 권장됩니다.

user.iduser handle이라고 부르기도 합니다.

user handle은 인증 프로세스를 수행하는 과정에서, 사용자를 식별하기 위해 사용됩니다. credential ID을 사용할 수도 있습니다.

  • user handle은 RP서버에 의해 생성되고, 사용자 계정에 등록된 모든 credential동일한 값을 갖습니다.

  • credential ID는 인증장치에 의해 생성되고, 각각의 credential고유한 값을 갖습니다.

pubKeyCredParams (required)

  pubKeyCredParams: [
    {
      type: "public-key",
      alg: -7 
    },
    {
      type: "public-key",
      alg: -257
    }
  ]

pubKeyCredParams은 인증장치가 전자서명을 수행할 때, 사용할 수 있는(RP서버에서 지원하는) 알고리즘 정보를 의미합니다. 객체의 순서는 서버의 선호도를 나타냅니다.

각각의 객체는 typealg를 멤버변수로 갖습니다. 이 중 type현재는 “public-key”를 고정 값으로 사용합니다.

algCOSE Algorithm Identifier를 나타냅니다.

위의 예시는 서버에서 ES256RS256 두 알고리즘을 지원하지만, ES256를 더 선호한다는 의미입니다.

timeout (optional)

 timeout: 60000

timeout은 클라이언트가 서버가 등록요청을 위해 기다려줄 시간을 의미합니다. milliseconds단위를 사용하므로, 위 예시는 1분을 의미합니다.

excludeCredentials (optional)

  excludeCredentials: [
      {
        "id": Uint8Array.from(window.atob("ufJWp8YGlibm1Kd9XQBWN1WAw2jy5In2Xhon9HAqcXE="), c=>c.charCodeAt(0)),
        "type": "public-key"
      },
      {
        "id": Uint8Array.from(window.atob("E/e1dhZc++mIsz4f9hb6NifAzJpF1V4mEtRlIPBiWdY="), c=>c.charCodeAt(0)),
        "type": "public-key"
      }
  ]

excludeCredentials는 이미 사용자가 등록한 credential 목록을 나타냅니다. 사용자에게 이미 등록된 인증정보가 있음을 알려주기 위해 사용됩니다.

authenticatorSelection (optional)

  authenticatorSelection: {
    authenticatorAttachment: {"cross-platform", "platform"},
    residentKey: "required",
    requiredResidentKey: ture,
    userVerification: "preferred",
  }

authenticatorSelection사용자가 등록할 수 있는 인증장치의 타입과 생성해야 하는 credential의 특징을 제한하는데 사용됩니다.

  • authenticatorAttachment
    • cross-platform
      사용자의 기기에 종속되지 않은, 외부 인증장치를 의미합니다.
    • platform
      사용자 기기에 종속된 인증 장치를 의미합니다.

    e.g) authenticatorAttachment: "cross-platform" 옵션을 전달할 경우, 사용자는 반드시 외부 인증장치를 사용해야 합니다.

  • userVerification
    • required
      사용자 검증이 반드시 필요합니다. 인증과정에서 UV flag를 검사합니다.
    • preferred
      가능하다면 사용자 검증을 수행합니다. 인증과정에서 UV flag를 검사하지 않습니다.
    • discouraged
      사용자 검증을 수행하지 않습니다.
  • residentKey

    권장되는 용어는 discoverable credential이지만, 여러 이유resident라는 용어가 그대로 사용되고 있습니다.

    residentKey 옵션이 사용 되는 이유는, credentialId가 아닌 RP서버에 대한 정보만을 이용해 연관된 credential(private key)를 찾도록 하기 위함입니다.

    이와 반대대는 개념의 단어는 server-side credential입니다. server-side credential을 사용하기 위해서 RP서버는 credentialId을 응답해야 합니다.

    보다 자세한 내용은 Resident Keys And The Future Of WebAuthn을 읽어보시길 권합니다.

    • required
      인증장치가 반드시 discoverable credential를 생성 해야 합니다. 불가능 할 경우 에러가 발생합니다.
    • preferred
      가능한경우 discoverable credential를 생성 해야 합니다. server-side credential를 생성해도 괜찮습니다.
    • discouraged
      가능한경우 인증장치에서 server-side credential을 우선적으로 생성해야 합니다. discoverable credential를 생성해도 괜찮습니다.
  • requireResidentKey

    • true
      residentKey 옵션 값이 required인 경우, 반드시 true 값을 사용합니다.

attestation (optional)

  attestation: "direct"

attestation옵션은 클라이언트가 등록 요청시 RP서버에 전달해야 하는 증명정보(attestation statement)에 대한 제약조건을 결정하는데 사용됩니다.

  • none
    클라이언트는 인증장치에 대한 증명정보를 요청에 포함하지 않아도 괜찮습니다.
  • indirect
    클라이언트는 인증장치에 대한 증명정보를 요청에 포함시켜야 합니다. 하지만 클라이언트가 원한다면 self-attestation을 이용해 RP서버에서 검증할 수 없는 attestation statement를 전달 할 수 있습니다.
  • direct
    클라이언트는 검증가능한(인증장치에 의해 생성된) 증명정보를 반드시 요청에 포함시켜야 합니다.
  • enterprise
    클라이언트는 특수한 정보가 포함된 증명정보를 요청에 포함시켜야 합니다. 해당 옵션은 인증수단으로서 특정 인증장치만을 이용하도록 제한하기 위해 사용됩니다.

extensions (optional)

extensions옵션은 클라이언트와 인증장치에서 추가적인 데이터 처리가 필요한 경우 사용됩니다. JSON 형식으로 제공되어야 합니다.

Create Credential

클라이언트(브라우저)는 서버로부터 응답받은 이 값들을 navigator.credentials.create()에 전달해 publicKeyCredential객체를 생성하게 됩니다.

const publicKeyCredentialCreationOptions = await apiStartRegistration();
const publicKeyCredential = await navigator.credentials.create({
    publicKey: publicKeyCredentialCreationOptions
});

console.log(publicKeyCredential);
/*
PublicKeyCredential {
    id: 'ADSUllKQmbqdGtpu4sjseh4cg2TxSvrbcHDTBsv4NSSX9...',
    rawId: ArrayBuffer(59),
    response: AuthenticatorAttestationResponse {
    clientDataJSON: ArrayBuffer(121),
    attestationObject: ArrayBuffer(306),
  },
  type: 'public-key'
}
*/

publicKeyCredential객체에 대한 이야기는 다음 포스팅에서 계속하도록 하겠습니다.


Reference

W3C WebAuthn Recommendation

WebAuthn guide

Yubico WebAuthn Developers Guide

 
 

잘못된 정보에 대한 피드백을 언제나 환영합니다. 많은 지적 바랍니다 :D

카테고리:

업데이트:

댓글남기기