7. Key Takeaways
● High level understanding of the WebAuthn specification and terminology
● How WebAuthn registration and login requests are structured and why
● How to parse and validate Credential Responses
● What attestation is and when to handle it
● How WebAuthn and FIDO2 Authentication make a more secure web
14. If you want to use Go
$ go get github.com/duo-labs/webauthn.io
$ cd $GOPATH/src/github.com/duo-labs/webauthn.io
$ go build -i; ./webauthn.io
15. If you want to use Docker
$ git clone https://github.com/duo-labs/webauthn.io.git
$ cd webauthn.io
$ docker build -t webauthn.io .
$ docker run --rm -p 9005:9005 webauthn.io
16. If you just want to follow along
$docker run --rm -p 9005:9005 duolabs/webauthn.io
22. CONFIDENTIAL INFORMATION PROPERTY OF DUO SECURITY, INC.
“In the beginning the Password was created.
This has made a lot of people very angry and
been widely regarded as a bad move.”
- Douglas Adams, kinda
23. CONFIDENTIAL INFORMATION PROPERTY OF DUO SECURITY, INC.
81% of breaches leveraged
either stolen and/or weak
passwords.
Source: 2017 Verizon Data Breach Investigations Report
28. CONFIDENTIAL INFORMATION PROPERTY OF DUO SECURITY, INC.
“The average… user has over
107 accounts registered to one
email address… In 2020, the
average number of accounts per
internet user will be 207”
- Dashlane, 2015
Guess the best solution is to buy a
password manager, right?
Definitely not get rid of passwords...
30. WebAuthn is a JavaScript API. It defines
two methods, create and get, that can
be used to register and assert ownership of
credential key pairs for a given website.
31. ● Developed by W3C and The FIDO Alliance
○ Includes companies like Google, Microsoft, Mozilla, Paypal, IBM, Yubico, and
Duo!
● Became a publicly recommended standard in March 2019
● Developed in part as a improvement upon the U2F standard
○ But includes many additional features and abilities
Introduction: WebAuthn
32. ● It allows for the creation of strong, attested, and scoped
credentials.
● The credentials are public and private key pairs
● Created with cryptographically strong and sound math.
● The authenticator can attest that it created a credential
● The credential is scoped for a single website
Introduction: WebAuthn
52. webauthn/protocol/options.go
type PublicKeyCredentialCreationOptions struct {
Challenge Challenge
RelyingParty RelyingPartyEntity
User UserEntity
Parameters []CredentialParameter
AuthenticatorSelection AuthenticatorSelection
Timeout int
CredentialExcludeList []CredentialDescriptor
Attestation string
}
The Relying Party should
hand back a response that
looks like this
Credential Creation Options
53. webauthn/protocol/options.go
type PublicKeyCredentialCreationOptions struct {
Challenge Challenge
RelyingParty RelyingPartyEntity
User UserEntity
Parameters []CredentialParameter
AuthenticatorSelection AuthenticatorSelection
Timeout int
CredentialExcludeList []CredentialDescriptor
Attestation string
}
These 3 are required, the
rest are optional but
recommended.
Credential Creation Options
54. webauthn/protocol/options.go
type PublicKeyCredentialCreationOptions struct {
Challenge Challenge
RelyingParty RelyingPartyEntity
User UserEntity
Parameters []CredentialParameter
AuthenticatorSelection AuthenticatorSelection
Timeout int
CredentialExcludeList []CredentialDescriptor
Attestation string
}
● Generated by RP server-side.
● Helps prevent replay attacks
● Stored until the registration is
complete
○ As session data, in a DB, etc...
Challenge Parameter
55. webauthn/protocol/entities.go
type RelyingPartyEntity struct {
Name string // Organization Name most likely
Icon string // URL of a image/logo/avatar
ID string // usually the origin url (https://ex.com)
}
● Only the name is required
○ ID can be overridden
○ ex.com can create an account for
test.ex.com
○ not vice versa
● ID must have HTTPS
Relying Party Information
56. webauthn/protocol/entities.go
type UserEntity struct {
Name string // Readable name used by the RP
Icon string
DisplayName string // Readable name chosen by the user
ID []byte // The RP’s ID for the user.
}
● Name and ID are required
● Display Name is used for the
user’s notification
User Information
57. webauthn/protocol/options.go
type CredentialParameter struct {
Type string // Should be “public-key”
Algorithm string // A COSE Algorithm Identifier
}
● Only public-key is currently
defined as a type
● The algorithm field should be a
value defined in the IANA COSE
Registry
○ -7 for ES256, -257 for RS256, etc
Credential Parameters
58. webauthn/protocol/options.go
type AuthenticatorSelection struct {
// Attachment could be “platform” or “cross-platform”
AuthenticatorAttachment string
RequireResidentKey boolean // Should the key be Resident
// Should the user be verified?
// Can be “required”, “preferred”, or “discouraged”
UserVerificationRequiremnet string
}
● None are required
● User Verification defaults to
“preferred”
● Authentication attachment tells
us how it should be connected
○ “cross-platform” is “roaming”
○ “platform” is internal to the
device
● We’ll talk more about resident
keys later
Authenticator Selection
59. webauthn/protocol/options.go
type PublicKeyCredentialCreationOptions struct {
Challenge Challenge
RelyingParty RelyingPartyEntity
User UserEntity
Parameters []CredentialParameter
AuthenticatorSelection AuthenticatorSelection
Timeout int
CredentialExcludeList []CredentialDescriptor
Attestation string
}
● The amount of time to allow the
authenticator/user to respond
● Not required by the client
○ May actually be overridden
● Uses milliseconds
● Recommend 60 seconds
○ That’s 60000 milliseconds!
Timeout Parameter
60. webauthn/protocol/options.go
type PublicKeyCredentialCreationOptions struct {
Challenge Challenge
RelyingParty RelyingPartyEntity
User UserEntity
Parameters []CredentialParameter
AuthenticatorSelection AuthenticatorSelection
Timeout int
CredentialExcludeList []CredentialDescriptor
Attestation string
}
● Allows us to exclude an
authenticator if it contains a
credential described in this list
● This is helpful for registering
multiple authenticators
● We’ll talk more about the
CredentialDescriptor
object later.
Credential Exclusion List
61. webauthn/protocol/options.go
type PublicKeyCredentialCreationOptions struct {
Challenge Challenge
RelyingParty RelyingPartyEntity
User UserEntity
Parameters []CredentialParameter
AuthenticatorSelection AuthenticatorSelection
Timeout int
CredentialExcludeList []CredentialDescriptor
Attestation string
}
● Tells us if we want the
authenticator to attest the
credential
● Three conveyance types
○ Direct
○ Indirect
○ None
Attestation Conveyence
66. In JSON
Provided from
navigator.credentials.create()
Returned at line 107 in
webauthn.io/static/dist/js/webauthn.js
{
"id":"AOB4OhswadyGM0GHREg...",
"rawId":"AOB4OhswadyGM0GHREg...",
"type":"public-key",
"response":{
"attestationObject":"o2NmbXRm...",
"clientDataJSON":"eyJjaGFsbG..."
}
}
Registration Response
67. ex.com
“The data I sent you is signed correctly and you
followed my options!”
Registration Response
71. In JSON
If you have the results you have to
parse them with this function.
// I create a credential with the extension args
credential = navigator.credentials.create(options)
extensions = credential.getClientExtensionResults()
// extensions contains a map of extension IDs
keyed to their results.
Registration Response
with Extensions
72. Extensions
● Depending on the extension, can be requested at
registration, login, or both
● Extensions can require input/output from the client and/or
the authententicator
● Most helpful extension right now is probably the
AppID extension for login
○ Allows for retro-support of legacy FIDO APIs
79. webauthn/protocol/options.go
type PublicKeyCredentialRequestOptions struct {
Challenge Challenge
Timeout int
RelyingPartyId string
AllowedCredentials []CredentialDescriptor
UserVerification string
}
● List of Credential
Descriptions to allow for
● Should contain the
credentials registered to
the user for an RP
Allowed Credential List
80. webauthn/protocol/options.go
type CredentialDescriptor struct {
Type string // Should be “public-key”
CredentialID []byte // Stored Credential ID
Transport []string // “usb”,“nfc”,“ble”,”internal”
// “lightning” transport added recently!
}
● Type will be “public-key”
● Credential ID is the stored ID
● What transports the
authenticator should use assert
the credential.
○ Internal should be used if the
authenticator is built in to the
device.
Credential Descriptor
81. webauthn/protocol/options.go
type PublicKeyCredentialRequestOptions struct {
Challenge Challenge
Timeout int
RelyingPartyId string
AllowedCredentials []CredentialDescriptor
UserVerification string
}
● Should the user be verified by
the authenticator?
○ Required
○ Preferred
○ Discouraged
● User Verification == “Human”
Verification
● Defaults to preferred
● If set to required, client will
exclude ineligible authenticators
User Verification Requirements
86. In JSON
Provided from
navigator.credentials.get()
Returned at line 107 in
webauthn.io/static/dist/js/webauthn.js
{
"id":"AOB4OhswadyGM0GHREg...",
"rawId":"AOB4OhswadyGM0GHREg...",
"type":"public-key",
"response":{
"authenticatorData":"o2NmbXRm...",
"clientDataJSON":"eyJjaGFsbG...",
"signature":"oASLKdlOMEIBaqs...",
"userHandle":"9AUAAAA...",
}
}
Assertion Response
87. In JSON
Provided from
navigator.credentials.get()
Returned at line 107 in
webauthn.io/static/dist/js/webauthn.js
{
"id":"AOB4OhswadyGM0GHREg...",
"rawId":"AOB4OhswadyGM0GHREg...",
"type":"public-key",
"response":{
"authenticatorData":"o2NmbXRm...",
"clientDataJSON":"eyJjaGFsbG...",
"signature":"oASLKdlOMEIBaqs...",
"userHandle":"9AUAAAA...",
}
}
Assertion Response
88.
89. Functions where we handle this data
● RequestNewCredential in webauthn.io/server/credential.go:17
○ Calls BeginRegistration in webauthn/webauthn/registration.go:19
● MakeNewCredential in webauthn.io/server/credential.go:66
○ Calls FinishRegistration in webauthn/webauthn/registration.go:105
● GetAssertion in webauthn.io/server/assertion.go:21
○ Calls BeginLogin in webauthn/webauthn/login.go:25
● MakeAssertion in webauthn.io/server/assertion.go:57
○ Calls FinishLogin in webauthn/webauthn/login.go:85
90. To Rebuild Your Code
## For Golang
## End the Go application (Ctrl-C)
$go run main.go
## For Docker
$docker down $DOCKER_ID // get ID with $docker ps
$docker build .
$docker run -p 9005:9005 --rm webauthn.io
93. In JSON
Provided from
navigator.credentials.create()
Returned at line 107 in
webauthn.io/static/dist/js/webauthn.js
{
"id":"AOB4OhswadyGM0GHREg...",
"rawId":"AOB4OhswadyGM0GHREg...",
"type":"public-key",
"response":{
"attestationObject":"o2NmbXRm...",
"clientDataJSON":"eyJjaGFsbG..."
}
}
Registration Response
95. type CollectedClientData struct {
Type CeremonyType
Challenge string
Origin string
TokenBinding TokenBinding
}
Client Data
● Contains the type of event
(ceremony)
○ webauthn.create
○ Webauthn.get
● The initial challenge
● The origin URL
○ According to the authenticator
● Token binding helps us bind the
session
● But how do we trust it?
97. Attestation and Attestation Objects
● Attestation Objects are packed in CBOR
○ Concise Binary Object Representation
● The Attestation Signature (most of the time) gives us proof
that the authenticator actually created the credential
● Up to the developer to check trust roots (with services like
FIDO’s Metadata Service)
● Read the spec or look in webauthn for instructions
98. Should I Handle or Request Attestation?
● Are you…
○ A bank?
○ A government agency?
○ Often attacked by nation states?
○ Excited to use the FIDO Metadata Service?
● If not, you probably don’t need to do attestation.
○ It depends on your threat model!
99. In JSON
Provided from
navigator.credentials.get()
Returned at line 107 in
webauthn.io/static/dist/js/webauthn.js
{
"id":"AOB4OhswadyGM0GHREg...",
"rawId":"AOB4OhswadyGM0GHREg...",
"type":"public-key",
"response":{
"authenticatorData":"o2NmbXRm...",
"clientDataJSON":"eyJjaGFsbG...",
"signature":"oASLKdlOMEIBaqs...",
"userHandle":"9AUAAAA...",
}
}
Assertion Response
102. Validation in 3 parts
1. Validate the data from the RP (Client Data)
○ Request Type, Request Origin, Challenge, etc
2. Validate the data from the Authenticator
○ Signature, Attestation data, AAGUID
3. Validate the credential
○ Public Key Format, Signature
103. Validation
● Check out the verification methods in webauthn/
○ protocol/credential.go
○ protocol/attestation.go
○ protocol/assertion.go
106. Resident Key Handling
● Gaining stable implementation in browsers
● Allows for mapping an RP ID to a credential, rather than to
a credential ID. Could also maybe support key syncing.
● The key is stored either on the authenticator and the
mapping is stored by the browser client, or the key is stored
(wrapped) outside of the authenticator.
○ Supporting “Incognito” tabs is being discussed
107. Account Recovery
Three main genres of recovery:
1. Alternate Credentials/Authenticators
○ Enrollment of multiple authenticators
○ Potentially the syncing of a single credential
2. Mutually Trusted/Delegated Authorities
○ A group that the relying party trusts to authenticate the user
3. Tokens of Identity
○ A token symbolizing a trust relationship between user and an MTA
○ i.e. State/National ID (non-digital)
4. Byzantine Relationships
108. Account Recovery
● Current guidance focuses mostly on Multiple authenticator enrollment
● Other methods I recommend (threat model dependent)
○ Push Messaging (Like duo, krypton, okta)
○ Email
○ If you’re an enterprise, help desk support flow is critical!
○ Quick linking
● Don’t fall back to passwords!
109. Account Recovery Prevention
● Use the API to find out if you can enroll new authenticators and relay
this through UI/UX.
● Potentially use quick links to add mobile devices and vice versa, if threat
model allows for it.
● Invest in user education! Account recovery can be more expensive than
educating users, especially if you’re a consumer-facing company.
110. FIDO2 Account Recovery Resources
● GDWG, CDWG, and EDWG are all thinking about this. If you’re a Fido
Alliance member, check out their work!
● I recommend checking out the login.gov webinar available through Fido’s
Youtube Account.
● I’m here if you need help!