본문 바로가기

Fido2/WebAuthn

라라벨 프로젝트에 WebAuthn 도입하기 (3) 등록 Flow 2 (Registration Flow) navigator.credentials.create

안녕하세요. 이전시간에는 PublicKeyCredentialCreationOptions에 대해서 알아보았는데요. 오늘은 navigator.credentials.create을 위해서 서버로부터 받은 publicKeyCredentialCreationOption을 디코딩하고 navigator.credentials.create메소드를 통해 publicKeyCredentail을 만드는 과정을 보겠습니다.

 

먼저 제가 발급한 publicKeyCredentialCreationOption입니다.

 

이후 이 publicKeyCredentialCreationOption이 어떻게 decode되는지 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
WebAuthn.prototype.register = function(publicKey, callback) {
  console.log(publicKey);
  let publicKeyCredential = Object.assign({}, publicKey);
  console.log(publicKeyCredential.user.id);
  publicKeyCredential.user.id = this._bufferDecode(publicKey.user.id);
  console.log(publicKeyCredential.user.id);
  publicKeyCredential.challenge = this._bufferDecode(this._base64Decode(publicKey.challenge));
  if (publicKey.excludeCredentials) {
    publicKeyCredential.excludeCredentials = this._credentialDecode(publicKey.excludeCredentials);
  }
 
  var self = this;
 
  console.log(publicKeyCredential);
 
  navigator.credentials.create({
    publicKey: publicKeyCredential
  }).then((data) => {
    self._registerCallback(data, callback);
  }, (error) => {
    self._notify(error.name, error.message, false);
  });
}
 
cs

 

this._bufferDecode 메소드와 this._base64Decode 메소드는 아래에 있습니다.

 

this._bufferDecode

1
2
3
4
5
WebAuthn.prototype._bufferDecode = function(value) {
  var t = window.atob(value)
  return Uint8Array.from(t, c => c.charCodeAt(0));
}
 
cs

 

this._base64Decode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
WebAuthn.prototype._base64Decode = function(input) {
  // Replace non-url compatible chars with base64 standard chars
  input = input.replace(/-/g, '+').replace(/_/g, '/');
 
  // Pad out with standard base64 required padding characters
  const pad = input.length % 4;
  if (pad) {
      if (pad === 1) {
          throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding');
      }
      input += new Array(5-pad).join('=');
  }
 
  return input;
}
 
cs

 

 

이후 다음과 같이 변합니다.

 

이후에 이 publicKeyCredential를 이용해서 navigator.credentials.create()에 인자값으로 넣어주세요 ㅎㅎ 원하시는 Option을 제대로 넣었다면 다음과 같은 화면이 나타납니다.

navigator.credentials.create()의 실행 결과인 PublicKeyCredential은 다음과 같습니다. 이 중에서 ClientDataJson과 AttensionObject가 중요한데요. ClientDataJson에는 challenge와 type 등 유효성 검사용 데이터가 들어있고 AttestationObject에는 추후 이용할 인증 정보가 들어 있습니다. 이후 서버에서는 이 두 데이터를 파싱한 후 처리를 할 예정입니다. 자세한 사항은 아래 Spec으로 확인해보세요 ㅎㅎ

 

 

 

 

이후에 서버에서는 이 데이터를 파싱(디코딩)한 후에 (1)유효한 요청인지 검사하고 (2)인증 정보를 저장합니다. 이것은 다음 포스트에서 함께 해보겠습니다. 또한 보시다시피 데이터들이 encoding, decoding 되는 과정이 꽤나 복잡하기 때문에 추후 정리해보겠습니다. ( 아래 참고로 dependencies 링크를 첨부했습니다, 아래 나오는 것들만 사용된다고 보심 될 것 같습니다 ㅎㅎ,, )

 

https://w3c.github.io/webauthn/#sctn-dependencies