Authentication done right: Consuming (and Serving) Oauth2.0

Authentication done right: Consuming (and Serving) Oauth2.0

Your brand has multiple products on the web. They all need authentication. But obviously, you’d maintain a common authentication and user database.
Also, in this age, you cannot make a login system without Login with [Facebook|Google|Twitter|...]
For the second thing, you need to consume Oauth2.0 (the industry standard now), for the first thing, you need to make your own Oauth server.
And you want all of this to happen securely (so yeah, little to no frontend JS)

37fbf83b7d45711e41e774e29fed710e?s=128

Arnav Gupta

October 26, 2018
Tweet

Transcript

  1. 1.

    Authentication Done Right Learnings from my journey of creating a

    federated login system in NodeJS Arnav Gupta
  2. 2.

    • Please do not consider me an expert on NodeJS,

    or cyber security. (My only expertise is memes). • This is not a “you should do it this way” sermon • This is our (Coding Blocks’) story – how we made our login system. • Some “security mishap” ™ examples about organizations are shown. I do not imply their systems are insecure or they are incompetent. Only that no one is infallible (except UIDAI) • Research on your own, and decide your own perf/security/UX tradeoffs. Disclaimer
  3. 4.

    © 2018 Coding Blocks, Arnav Gupta Client App 1 Client

    App 1 Client App 1 Login / User Management System
  4. 5.

    What have we built ? OAuth2 client • Login via

    Facebook/Twitter/Github/Google is via their OAuth interface • Connect to Facebook after Login via Twitter (also OAuth) • Migrating our old system users to new one invisibly (old interfaced massaged into OAuth) © 2018 Coding Blocks, Arnav Gupta
  5. 6.

    Client App 1 Client App 1 Client App 1 ©

    2018 Coding Blocks, Arnav Gupta Login / User Management System our own old system migrate
  6. 7.

    Ingredients ? • PassportJS – Literally Auth0 has made everything

    open source with which you can D.I.Y. an exact Auth0 clone • PostgreSQL (with Sequelize) • bcrypt – (native) © 2018 Coding Blocks, Arnav Gupta bcrypt
  7. 8.

    What have we built ? OAuth2 server • Single Sign

    On (with Federated Identity) • All apps login via account.codingblocks.com (and get profile/role details) • Anyone can make an app and use login via Coding Blocks © 2018 Coding Blocks, Arnav Gupta
  8. 9.

    Login / User Management System © 2018 Coding Blocks, Arnav

    Gupta other apps . . . auth+ roles auth + github … roles update coupons/demographics
  9. 10.

    Ingredients • oauth2orize – Creates a OAuth 2.0 server automagically

    • nodemailer (+sendgrid) email verify, reset and stuff • speakeasy – TOTP for 2-factor login © 2018 Coding Blocks, Arnav Gupta
  10. 11.

    Our Guiding Principles © 2018 Coding Blocks, Arnav Gupta Basic

    tenets on which our architecture hinges
  11. 12.

    No JS • 100% working in no-JS browsers • Forget

    about XSS • CSS sufficient for responsive • Secure HttpOnly cookies • Perspective: Gmail works sans JS • XSS protection is HARD, a f • Performance ++ • Bonus: Better for SEO © 2018 Coding Blocks, Arnav Gupta
  12. 13.

    bcrypt • Use C++, not JS lib • scrypt less

    tested, maybe better • PBKDF2 also fine (preference) • Just use bcrypt, don’t tinker • Salts – as random as possible • Work factor (rounds) ≈ 10 is ok • Pepper not needed (methinks) • Stick to blowfish/pbkdf2 - KISS © 2018 Coding Blocks, Arnav Gupta
  13. 14.

    2FA • Encourage 2FA • Don’t force it • speakeasy

    – TOTP (must) • SMS / Email optional (recommend) • TOTP fallback to SMS/Email • Ideal: Redo 2FA on session resume © 2018 Coding Blocks, Arnav Gupta
  14. 15.

    No JWT • JWTs have their place, not here •

    Server-enforced logout needed • Token lookup time != perf barrier • Remember JWT = Cookie for GDPR • Stateful JWT = Session token only • JWT is avoidable extra knowledge © 2018 Coding Blocks, Arnav Gupta
  15. 16.

    Single UI • Only one form takes password • Trust

    browsers • NO API based login for clients • You are NOT Facebook/Google • Reduce MITM vectors • Browsers enforce & show HTTPS • Consistent redirect UX for users • User’s internet too slow for HTML? © 2018 Coding Blocks, Arnav Gupta
  16. 18.

    Step 1: Decided what we cannot protect “One of the

    main cyber-risks is to think they don’t exist. The other is to try to treat all potential risks. - Stephane Nappo ” © 2018 Coding Blocks, Arnav Gupta
  17. 20.

    • User sharing login credentials (or looking over shoulder) •

    User’s browser is compromised (or malicious web extensions) • Social-engineered hacks • Users behind 3rd party SSL certificates What we kept out of our scope of protection
  18. 25.

    Quiz Time! © 2018 Coding Blocks, Arnav Gupta 401 vs

    403 • Error Name of 401 ? Can a logged in user get 401 ? • Error name of 403 ? Can a logged out user get 403 ?
  19. 26.

    Answers © 2018 Coding Blocks, Arnav Gupta 401 vs 403

    • 401: Unauthorized (but really means unauthenticated) • 403: Forbidden (which means authenticated but not authorized)
  20. 27.

    Authentication via Authorization © 2018 Coding Blocks, Arnav Gupta In

    other words, OAuth SSO via social media accounts
  21. 40.

    © 2018 Coding Blocks, Arnav Gupta https://api.github.com/profile {header: auth_token =

    xxxx } profile data fetching in browser profile page name email username
  22. 43.

    © 2018 Coding Blocks, Arnav Gupta https://auth.github.com/token {header: grant_code =

    xxxx } auth_token https://api.github.com/profile {header: auth_token = xxxx } name email username profile page
  23. 44.

    © 2018 Coding Blocks, Arnav Gupta Open URL Fetch Page

    Show auth UI Fetch 3rd Party Auth Page 3rd Party Challenge Fulfill challenge Request 3rd party login Verify Challenge Redirect to client (with AUTH_TOKEN) Fetch Client Page Show Client Page Fetch Profile detauls (using AUTH_TOKEN) Send profile details
  24. 45.

    © 2018 Coding Blocks, Arnav Gupta Open URL Fetch Page

    Show auth UI Fetch 3rd Party Auth Page 3rd Party Challenge Fulfill challenge Request 3rd party login Verify Challenge Redirect to client (with GRANT_CODE) Fetch Client Page Show Client Page Request ACCESS_TOKEN using GRANT_CODE Provide ACCESS_TOKEN Fetch Profile detauls (using AUTH_TOKEN) Send profile details
  25. 47.

    Basic security hygiene We came a long way without taking

    care of these. You shouldn’t • CSRF protection (use csurf) • Basic ExpressJS protection (headers, origins, content types) – use helmet • Importance of statelessness (when we moved to cluster mode we had to do major rewrite as sessions were in memory) © 2018 Coding Blocks, Arnav Gupta
  26. 48.

    Basic Security vs Overkill Checklist • X-Frame-Options (likely you want

    - DENY) : helmet/frameguard • Content-Security-Policy ◦ script-src - helps against XSS, can completely disable frontend JS ◦ use specific CDN img-src, style-src, font-src ◦ use whitelist for form-action and connect-src • Http Public Key Pinning - Hard to maintain, attacker can pin wrong cert, Chrome 72+ drops support. • HTTP Strict Transport Security – You can enforce SSL on application layer. Also try HTTPS for at least 6-9 months without issues before trying this. You may lock out users. Catch 22 – renewing an expired LetsEncrypt cert
  27. 49.

    CSRF protection • Only for endpoints that will be hit

    by our own frontend. • Do not implement on endpoints where external clients with POST (eg. the API) © 2018 Coding Blocks, Arnav Gupta const csurf = require('csurf') app.use(csurf({cookie: true})) app.get('/form', (req, res) => res.render('form', { _csrf: req.csrfToken() })) app.post('/submit', (req, res) => { // process data }) <form action="/submit" method="POST"> <input type="hidden" name="_csrf" value="{{_csrf}}"> <input type="text" name="username"> <input type="password" name="password"> </form>
  28. 50.

    SQL Injection is very very real Thumbrule: ORM prepared statements

    help. BUT . . . • Step 1: Make sure you use prepared/escaped queries. Manually escape rawQueries • Sequelize 3.x suffered thrice from SQLi vuln. (All fixed in >= v3.20) • Defense in depth: validate every layer (client, route, controller, model) © 2018 Coding Blocks, Arnav Gupta
  29. 51.

    Specs are important Being incomplete is ok, but being non-compliant

    is not • Specifications like OAuth or other ISO/IEEE/IETF ratified standards have gone through multiple RFC periods, technical peer reviews • However enticing – try to avoid ‘tiny workarounds’ or ‘small changes’ • Fine to keep some features unimplemented, but careful not to make spec- compliance impossible in feature. © 2018 Coding Blocks, Arnav Gupta
  30. 52.

    • Used custom “our own way” of refresh tokens All

    client apps use common OAuth libraries, which have support for spec- compliant way. Ended up breaking libraries, editing lines in node_modules, creating own oauth library, finally giving up. • Didn’t consider client credential grant to be future use case. Major rewrite to support payments app to read data of user outside of user token scope Ignored specs: Burned our fingers
  31. 53.

    • Refresh tokens (people will re-auth after expiry) • Scopes

    (keep scope data structure, just use ‘profile’ or ‘*’ scope for all) • Client-scoped tokens (non-user authorizations) • Password grant type – actually an insecure backwards compatible vestige, do not implement (refer: Single UI) Specifically in OAuth, we can ignore / defer …
  32. 54.

    State Management is UX itself In a 2-level SSO maximum

    user drops happen when we fail to pursue all redirectTo and returnTo scenarios • unverified email > account page > verify > back to exact same screen • shopping first time > add address > back to same state of cart • client app > sso portal > 3rd party sso > sso portal > client app (no drops) • refrain from window.open (XSS vectors, distraction, non linear) © 2018 Coding Blocks, Arnav Gupta
  33. 59.

    Separation of Concerns Authentication vs Authorization vs Data API •

    Client apps depend on Data API – make it versioned • Client apps depend on authorization flow – have support for scopes • Client apps do not depend on authentication flow © 2018 Coding Blocks, Arnav Gupta
  34. 60.

    Separation of Concerns What in client and what on SSO

    server ? • Thumbrule: If needed by more than 2 apps, centralize it • Thumbrule: If data does not belong to user, do NOT centralize it • Roles: Present on both SSO and client • Access social media info – always via the SSO api © 2018 Coding Blocks, Arnav Gupta
  35. 61.

    Separation of Concerns Data Synchronisation • At every user <->

    client auth, we verify data from SSO server • For passive data changes to reflect (when user is not using), support for data sync webhooks on clients, which SSO server triggers • For data updates on SSO server, do it via generic API using user-scoped tokens. No “special endpoints for special clients”. © 2018 Coding Blocks, Arnav Gupta
  36. 62.

    Better mileage with existing standards (POLA) We found there is

    an ISO standard for a whole lot of things! • For demographics (country/state), we use ISO 3611 codes as primary keys, after wasting time migrating autoincr int ids multiple times • RFC6750 for bearer token usage • Standard headers, params are handled by many libraries in a special ways, benefits you forgo if deviating from standards © 2018 Coding Blocks, Arnav Gupta
  37. 63.

    Analytics and Monitoring Be careful what you log • No

    JS = no client side analytics. Which is good. Adblockers spoil data • Make sure you obfuscate critical data in logs. 3rd party monitoring means data is stored with them, not you (legal implications) • Use standard HTTP error codes (you have no idea how much that helps) • Careful about log-all wrappers like newrelic, Graylog, Sentry © 2018 Coding Blocks, Arnav Gupta
  38. 64.

    Common mistake • 2018 Github – logging passwords • 2018

    Twitter – logging password • Wide speculation – they were both using similar Ruby based logging service that dumps all HTTP requests © 2018 Coding Blocks, Arnav Gupta
  39. 65.

    Explain errors, to the user Obscure errors are reported with

    0 details and you can’t fix your system if you don’t get exact bugs reported • Wrong email O R password << this is useless • Something went wrong << ugghhh no • Obscuring things don’t make them secure (hackers dig deeper, actual users get frustrated) © 2018 Coding Blocks, Arnav Gupta
  40. 68.

    We did this too, and ended up frustrated with .

    . . • I can’t login…. • Why? • I just can’t © 2018 Coding Blocks, Arnav Gupta
  41. 69.

    Don’t be big brother Asking for data or extra permission

    lowers conversions • Take as few details as needed. Clients can request more, come back and fill those later (eg. address only when buying physical product) • Social logins have less steps if you ask for less scopes. Fetching too much data was detrimental (discrepancies) • Refrain from dark patterns (user should feel in control) © 2018 Coding Blocks, Arnav Gupta
  42. 70.

    Social Login with extra perms © 2018 Coding Blocks, Arnav

    Gupta • Ever changing API docs of 3rd party login providers • Login with Facebook/Google/Twitte r not working – common occurrence; especially after Cambridge Analytica Login with Google on Disqus, circa 2018
  43. 72.

    Try to remain generic Specifics are hard to change later

    • Assume country can be anything. Don’t assume +91 etc etc • More roles in future possible. More social logins possible. • The AWS/Amazon formula – to build better, think you’re building for 3rd party clients • To integrate custom systems like Discus, we have OAuth consuming proxy © 2018 Coding Blocks, Arnav Gupta
  44. 73.

    Deduplication is H A R D Uniquely identifying users is

    painful, do it at your own peril • User has Facebook and Twitter acc with separate emails. Wants to merge • Emails with dots and plus • IP Address of login client (to check account sharing) • 2FA via mobile/email vectors can help © 2018 Coding Blocks, Arnav Gupta
  45. 74.

    Secure – even from yourself Your developers are also ‘outsiders’

    for the system • Create a dev db. Anonymize the names and demographic data • Open source it (ok at least pretend this is an open source project) • Never ever ever ever ever ask users to send any detail aside from email id • Even at MVP/Prototype stage no ‘admin:admin’ credentials please! © 2018 Coding Blocks, Arnav Gupta
  46. 75.

    Security is actually very simple* * Terms and Conditions Apply

    • Security vs User Experience tradeoff is NOT NECESSARY • Security vs Developer Experience tradeoff IS VERY VERY REAL • There is no “dev environment” – it is always production • Do not bullshit yourself with “we’ll secure it later” • Actually follow the basic security tips we know from 5th grade © 2018 Coding Blocks, Arnav Gupta
  47. 76.

    If you think you are a cyber-security expert, that’s the

    first sign you aren’t © 2018 Coding Blocks, Arnav Gupta “It is better to remain silent and be thought a fool than to open one's mouth and remove all doubt. - Mark Twain or Abraham Lincoln ”
  48. 82.

    Inspirations Other similar systems • StackExchange Network (imo, the best

    implementation of dual layer SSO) • Closer home – HasGeek’s lastuser © 2018 Coding Blocks, Arnav Gupta
  49. 83.

    Credits Won’t be possible without • Jared Hanson - Auth0

    Chief Arch, author of Passport and oauth2orize • Eran Hammer – OAuth 1.0 author, and critic of Oauth 2.0 – for telling us which parts of OAuth 2.0 are overkill and unnecessary © 2018 Coding Blocks, Arnav Gupta