GitHub is currently working on migrating to WebAuthn!We hit a *lot* of snags. Some things that would help others avoid our pain points:
- Examples of how to migrate from U2F.
- Information about the appid extension (this used to be much harder to find!).
- Examples of how RP ID scoping works (when I read the spec, I originally assumed that "registrable domain suffix" was a formal synonym for eTLD+1, but it's not).
- Which old values (e.g. key handle) can be reused? Does any conversion need to happen?
- A good library for the relevant server language, with:
- Support for setting RP ID as well as using the appid extension.
- Ergonomics (e.g. automatically serializing webauthn requests to/from JSON — see below).
- Test fixtures.
- A de facto/official convention for how to serialize the WebAuthn API input/output on the wire, and perhaps some small libraries for this. (WebAuthn API input/output looks essentially like JSON, with the awkward detail that binary data values are ArrayBuffers. It seems really minor, but this forces every implementation to make a custom design decision where U2F "just worked". Sample implementations often convert to base 64, but don't agree on websafe vs. normal base 64. It's also tempting to "flatten" the JSON while implementing a transformation, but that could hurt forward compatibility.)
- Up-to-date type definitions in TypeScript and Flow.
- TypeScript has a few stale details from older spec versions.
- Flow landed some partial definitions that made it harder for us than when there were no definitions at all. There are still no full definitions. 😔
And some extra things that would be nice:
- WebAuthn mock implementations in JS for headless browser tests.
- An explainer on how the different physical access concepts interact: user presence vs. user verification vs. platform authentication vs. prevent silent access. This is a little confusing.
- A reference on future considerations — if we first migrate from U2F to webauthn with feature parity, do we need to keep anything in mind if we want to support "single-factor" auth in the future? Is it worth storing attestations from registrations?
- How strong is the recommendation for 64 bytes as the user handle? If we were to use hashed/encrypted/encoded values (or even just reused public user IDs), what would that do to the threat model?
- An explanation of what algorithm IDs should be used. Is it fine to just assume consumer security keys will use -7 for the indefinite future, or might that paint us into a corner?
- A reference on browser behaviours, e.g.
- In practice, what kind of browser UI will cover our web UI? Is there a best practice for what context to give in the browser?
- We have some in-page modal dialogs are almost completely covered by Chrome's UI. Should we still have a UI, or should we trust every browser to "do the talking"?
- We have some flows where the U2F request happens "in the background" — we show a password field along with a spinner stating "Alternatively, press the button on your security key…". Is it reasonable to try to adapt this to WebAuthn?
- How should we split the responsibility of explaining what went wrong to the user? (U2F provided more detailed errors than WebAuthn does. When WebAuthn gives us a generic error, can we trust the browser to explain what happened instead so that we don't have to recap it?)
- Is there anything that would work fine on one platform but not others? (For example, I believe the attestation format is different on Android. You need to pick a server library that handles this.)
We've contributed a few miscellaneous fixes for these issues, and hope to share more of what we learned. For now, though, we're focusing on shipping WebAuthn for github.com accounts — I can't share an exact timeline, but we would almost certainly be ready before any practical deprecation date for Chrome.
If you're doing attestation, it could be worth storing the AAGUID from the authenticator, but it probably isn't necessary to store the statement after verifying it.
On Thu, May 30, 2019 at 1:05 PM Lucas Garron <lga...@chromium.org> wrote:GitHub is currently working on migrating to WebAuthn!We hit a *lot* of snags. Some things that would help others avoid our pain points:
- Examples of how to migrate from U2F.
- Information about the appid extension (this used to be much harder to find!).
- Examples of how RP ID scoping works (when I read the spec, I originally assumed that "registrable domain suffix" was a formal synonym for eTLD+1, but it's not).
- Which old values (e.g. key handle) can be reused? Does any conversion need to happen?
- A good library for the relevant server language, with:
- Support for setting RP ID as well as using the appid extension.
- Ergonomics (e.g. automatically serializing webauthn requests to/from JSON — see below).
- Test fixtures.
- A de facto/official convention for how to serialize the WebAuthn API input/output on the wire, and perhaps some small libraries for this. (WebAuthn API input/output looks essentially like JSON, with the awkward detail that binary data values are ArrayBuffers. It seems really minor, but this forces every implementation to make a custom design decision where U2F "just worked". Sample implementations often convert to base 64, but don't agree on websafe vs. normal base 64. It's also tempting to "flatten" the JSON while implementing a transformation, but that could hurt forward compatibility.)
- Up-to-date type definitions in TypeScript and Flow.
- TypeScript has a few stale details from older spec versions.
- Flow landed some partial definitions that made it harder for us than when there were no definitions at all. There are still no full definitions. 😔
Thank you for that! That may make excellent fodder for some updates to MDN or documentation that we host ourselves.
A few points where I can give specific responses:And some extra things that would be nice:
- WebAuthn mock implementations in JS for headless browser tests.
In progress.
- An explainer on how the different physical access concepts interact: user presence vs. user verification vs. platform authentication vs. prevent silent access. This is a little confusing.
- A reference on future considerations — if we first migrate from U2F to webauthn with feature parity, do we need to keep anything in mind if we want to support "single-factor" auth in the future? Is it worth storing attestations from registrations?
- How strong is the recommendation for 64 bytes as the user handle? If we were to use hashed/encrypted/encoded values (or even just reused public user IDs), what would that do to the threat model?
64 bytes is a maximum length. It can certainly be shorter. The important requirement is that it not contain PII (so don't use public user IDs, at least encrypt them first). When creating resident credentials (i.e. what I think you're referring to as "single-factor") the user-id is what you get back to identify the user, and it may be accessible to anyone who has physical access to the device. (Thus the requirement not to include PII.)
--
To unsubscribe from this group and stop receiving emails from it, send an email to security-dev...@chromium.org.
GitHub is currently working on migrating to WebAuthn!
We hit a *lot* of snags. Some things that would help others avoid our pain points:
We've contributed a few miscellaneous fixes for these issues,
and hope to share more of what we learned.
The problem is that we no longer have a way of putting existing U2F registrations on the "excludeCredentials" list. While you can include the key handle, there's no way to pass the AppID. This means that the RP will never test if an authenticator responds to the legacy AppID, and thus the existing credential is effectively ignored.In practice, this means you can make a second registration for the same token via WebAuthn. There's no apparent way to distinguish this registration server-side, leading to a confusing experience for users who accidentally re-register their authenticator.
I'd love to see some way to support deconflicting existing U2F registrations during the WebAuthn credential creation process. As a simple first proposal, there could be an "appid" registration extension for use with the credential exclusion list only. The extension would provide no output. This supports the goal of not allowing new U2F registrations while also detecting existing U2F registrations correctly.
I'd also like to echo the feedback about marshaling / unmarshalling ArrayBuffers being somewhat painful and unintuitive. Having all the data already encoded in U2F made for a very easy integration experience.
The "FIDO AppID Extension" (https://www.w3.org/TR/webauthn/#sctn-appid-extension) clearly calls out that the WebAuthn API will not create backwards-compatible registrations. Empirically, both Chrome and Firefox will reject "navigator.credentials.Create()" calls that specify this extension.The problem is that we no longer have a way of putting existing U2F registrations on the "excludeCredentials" list. While you can include the key handle, there's no way to pass the AppID. This means that the RP will never test if an authenticator responds to the legacy AppID, and thus the existing credential is effectively ignored.In practice, this means you can make a second registration for the same token via WebAuthn. There's no apparent way to distinguish this registration server-side, leading to a confusing experience for users who accidentally re-register their authenticator.I'd love to see some way to support deconflicting existing U2F registrations during the WebAuthn credential creation process. As a simple first proposal, there could be an "appid" registration extension for use with the credential exclusion list only. The extension would provide no output. This supports the goal of not allowing new U2F registrations while also detecting existing U2F registrations correctly.