🔑
GoでWebauthを試してWeb Authenticationで登録する流れを追う
概要
下記で提供されているWebAuthn関係のライブラリのexampleの動くものを作って、体系的にWebAuthnの理解をしたかった。
動くサンプルのソースコードは下記。
goのversionを合わせて、下記のコマンドを実行し、http://http://localhost:8080/
にアクセスすれば再現できると思います。
$ go mod tidy
$ go run .
UI
登録
↓
↓
↓
ログイン
↓
registerしていないログインは失敗する
コード解説
私はセキュリティの専門家ではないので、情報の正当性については責任を負いかねます。
登録
BeginRegistration()
webauthnライブラリに依存する部分は下記です。
①: registerOptionsという無名関数を定義、webauthnのprotocolのPublicKeyCredentialCreationOptionsを引数にとって、CredentialExcludeListにuser.CredentialExcludeList()
を代入。
②: ユーザーと①で作成した無名関数を渡して、返却値で使用するoptionsと、クッキーで使用するセッションデータを作成。あとで"registration"という名前のクッキーでHTTPヘッダーに込めて返却。
func BeginRegistration(w http.ResponseWriter, r *http.Request) {
..
// ①
registerOptions := func(credCreationOpts *protocol.PublicKeyCredentialCreationOptions) {
credCreationOpts.CredentialExcludeList = user.CredentialExcludeList()
}
..
// ②
options, sessionData, err := Wc.BeginRegistration(
user,
registerOptions,
)
webauthnのメソッドである、BeginRegistration
を見ていきます。
- サーバーでchallengeというランダム値を生成
- 渡したuserとconfigから、構造体を作成
- defaultRegistrationCredentialParametersはアルゴリズム達がある
- 初期化した上記の構造体達を使って、登録時の公開鍵生成の構造体を作成
- urlエンコードされたchallengeやuser情報をセッションデータを作成
- 秘密鍵生成の構造体とセッションデータを返却
これで、jsonでクライントに一旦返却します。
BeginRegistration()後のクライアント(index.js記載の処理)
- 返却された公開鍵生成の構造体をデコードして、チャレンジ/ユーザーID/公開鍵を取り出し、公開鍵を持って標準化されたウェブ認証APIを呼び出す
-
navigator.credentials.create()
で認証器(MacbookやYubiKey)に登録 -
navigator.credentials.create()
の返却値の認証情報を用いて、サーバーにPOSTでFinishRegistration()
を叩く
FinishRegistration()
- "registration"という名前で保存したクッキーから、セッション情報を復元
- クライアントからの認証情報をライブラリでパースし、ユーザー情報/セッション/パースされた認証情報を照合し、Credential構造体を作成
- Credential構造体をuserのcredentialsに入れて保存し、セッションを削除し登録完了です。(※credentialsは
user.go
に下記で定義されており、名前は任意)
type User struct {
id uint64
name string
displayName string
credentials []webauthn.Credential
}
次回はログイン周りを見ていきたいと思います。
読んでいただきありがとうございました!
参考
Discussion