Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go Passwordless with WebAuthn in Ruby

Go Passwordless with WebAuthn in Ruby

Nowadays, passwords are still our most common authentication method. However, they are not secure enough and have terrible UX.

Therefore, big industry players in the FIDO Alliance like Google, Mozilla, Apple, Amazon (among others) collaborated together to find a solution. WebAuthn was born and eventually became a W3C standard enabling users to authenticate on the web using public-key cryptography together with biometrics.

This talk will allow you to learn what WebAuthn is and how it works. You’ll also see how any Ruby app can easily get the level of authentication security and UX users deserve.

Braulio Martinez

April 24, 2023
Tweet

Other Decks in Technology

Transcript

  1. WhatsApp’s authentication Factors: ◦ Phone number ownership - Possession ▪

    Proved by typing a code received via SMS ◦ [Optional] 6-digit PIN - Knowledge
  2. Passwords ◦ Prone to phishing, brute force, etc ◦ All

    users compromised if hackers access a DB or a server ◦ Repetition across systems ◦ Bad UX
  3. 81% of all hacking related breaches were a consequence of

    stolen passwords https://tinyurl.com/eumfschr
  4. Most used second factors ◦ One Time Password (OTP) via

    SMS ◦ Time based OTP or TOTP via Google Authenticator
  5. Only 28% of users use some kind of second authentication

    factor https://tinyurl.com/mpk979xz
  6. 89% of organizations suffered at least one phishing attack in

    the course of 2022 with an average cost of $2.19M https://blog.hypr.com/press-releases/hypr-the-leader-in-phishing- resistant-mfa-raises-25m
  7. WebAuthn (Web Authentication) is a standard that defines a set

    of rules for APIs to enable users to strongly register and authenticate on web applications using public key based cryptography.
  8. +

  9. The Entities ◦ Authenticator => User Device ▪ Creating and

    holding credentials securely, signing ◦ Client => Web Browser ◦ Relying Party => Web App
  10. # app/views/registrations/new.html.erb <%= form_with url: registration_path, ... do |form| %>

    <%= form.text_field :username %> <%= form.text_field :nickname %> <%= form.submit ‘Sign Up’ %> <% end %>
  11. # app/controllers/credentials_controller.rb def create user = User.new(...) options = WebAuthn::Credential.options_for_create(...)

    if user.valid? session[:current_registration] = { challenge: options.challenge, ... } respond_to do |format| format.json { render json: options } end end end
  12. # app/views/sessions/new.html.erb <%= form_with url: session_path, ... do |form| %>

    <%= form.text_field :username %> <%= form.submit ‘Sign In’ %> <% end %>
  13. # app/controllers/sessions_controller.rb def create user = User.find_by(...) if user options

    = WebAuthn::Credential.options_for_get( allow: user.credentials.pluck(:external_id), ... ) session[:current_authentication] = { challenge: options.challenge, ... } respond_to do |format| format.json { render json: options } end end end
  14. # app/javascript/credentials.js navigator.credentials.get({ publicKey: { allowedCredentials: [{ id: registeredCredId, …

    }] } }).then(function(credential) { authenticateCredentialWithServer(credential); });
  15. # app/javascript/credentials.js navigator.credentials.get({ publicKey: { allowedCredentials: [{ id: registeredCredId, …

    }] } }).then(function(credential) { authenticateCredentialWithServer(credential); });
  16. # app/controllers/credentials_controller.rb def authenticate credential = WebAuthn::Credential.from_get(params[:credential]) registered_credential = current_user

    .webauthn_credentials .find_by(webauthn_id: credential.id) credential.verify(…, public_key: registered_credential.public_key) end
  17. # app/controllers/credentials_controller.rb def authenticate credential = WebAuthn::Credential.from_get(params[:credential]) registered_credential = current_user

    .webauthn_credentials .find_by(webauthn_id: credential.id) credential.verify(…, public_key: registered_credential.public_key) # return success end
  18. WebAuthn as a 2nd & 3rd Factor 1st: Password -

    Knowledge 2nd: WebAuthn Credential - Possession 3rd: WebAuthn User Verification - Knowledge or Inherence
  19. WebAuthn as a 2nd & 3rd Factor 1st: Password -

    Knowledge 2nd: WebAuthn Credential - Possession 3rd: WebAuthn User Verification - Knowledge or Inherence
  20. WebAuthn as 1st & 2nd factor 1st: WebAuthn Credential -

    Possession 2nd: WebAuthn User Verification - Knowledge or Inherence
  21. Wins! ✅ No brute force ✅ No sensitive data (secrets)

    in the Server ✅ No phishing ✅ No man-in-the-middle attacks
  22. Passkeys Features (many WIP) • Browser Autofill UI • Cross

    device authentication authenticators • Cross device authentication client • Device Public Key (DPK)
  23. Disclaimer: a few of these browsers/platforms might still be using

    legacy U2F to talk to authenticators WebAuthn Platform/Browser Support (April 2023) iOS Android Windows macOS Linux Chrome Edge Safari - - - Firefox Brave
  24. ◦ webauthn-ruby v3.X.X ▪ Maintenance and staying on edge on

    dependencies ▪ Evolving as well as the standard keeps changing ◦ webauthn + devise, keep pushing as a second factor ◦ Passkeys
  25. Thanks to webauthn-ruby contributors! ◦ @grzuy - Gonzalo Rodriguez (former

    Cedarcode) ◦ @bdewater - Bart @Thatch (former Shopify) ◦ @santiagorodriguez96 - Santiago Rodriguez @Cedarcode ◦ @sorah - Sorah Fukumori @Cookpad ◦ @lgarron - Lucas Garron @Github ◦ @padulafacundo - Facundo Padula (former Cerdacode)