Slide 1

Slide 1 text

Authentication Done Right Learnings from my journey of creating a federated login system in NodeJS Arnav Gupta

Slide 2

Slide 2 text

● 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

Slide 3

Slide 3 text

What have we built ? © 2018 Coding Blocks, Arnav Gupta

Slide 4

Slide 4 text

© 2018 Coding Blocks, Arnav Gupta Client App 1 Client App 1 Client App 1 Login / User Management System

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

Client App 1 Client App 1 Client App 1 © 2018 Coding Blocks, Arnav Gupta Login / User Management System our own old system migrate

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Login / User Management System © 2018 Coding Blocks, Arnav Gupta other apps . . . auth+ roles auth + github … roles update coupons/demographics

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

Our Guiding Principles © 2018 Coding Blocks, Arnav Gupta Basic tenets on which our architecture hinges

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Let’s start from the basics © 2018 Coding Blocks, Arnav Gupta

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

© 2018 Coding Blocks, Arnav Gupta

Slide 20

Slide 20 text

● 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

Slide 21

Slide 21 text

Identification vs Authentication vs Authorization © 2018 Coding Blocks, Arnav Gupta

Slide 22

Slide 22 text

© 2018 Coding Blocks, Arnav Gupta

Slide 23

Slide 23 text

© 2018 Coding Blocks, Arnav Gupta

Slide 24

Slide 24 text

© 2018 Coding Blocks, Arnav Gupta

Slide 25

Slide 25 text

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 ?

Slide 26

Slide 26 text

Answers © 2018 Coding Blocks, Arnav Gupta 401 vs 403 ● 401: Unauthorized (but really means unauthenticated) ● 403: Forbidden (which means authenticated but not authorized)

Slide 27

Slide 27 text

Authentication via Authorization © 2018 Coding Blocks, Arnav Gupta In other words, OAuth SSO via social media accounts

Slide 28

Slide 28 text

© 2018 Coding Blocks, Arnav Gupta

Slide 29

Slide 29 text

© 2018 Coding Blocks, Arnav Gupta

Slide 30

Slide 30 text

© 2018 Coding Blocks, Arnav Gupta http://account.codingblocks.com

Slide 31

Slide 31 text

© 2018 Coding Blocks, Arnav Gupta https://account.codingblocks.com https://account.codingblocks.com

Slide 32

Slide 32 text

© 2018 Coding Blocks, Arnav Gupta https://account.codingblocks.com login page https://account.codingblocks.com

Slide 33

Slide 33 text

© 2018 Coding Blocks, Arnav Gupta login page Click: Login with Github

Slide 34

Slide 34 text

© 2018 Coding Blocks, Arnav Gupta https://github.com/login client_id = xxxx redirect_uri = xxxx

Slide 35

Slide 35 text

© 2018 Coding Blocks, Arnav Gupta github login page

Slide 36

Slide 36 text

© 2018 Coding Blocks, Arnav Gupta github login page username password

Slide 37

Slide 37 text

© 2018 Coding Blocks, Arnav Gupta github login page verify username & password

Slide 38

Slide 38 text

© 2018 Coding Blocks, Arnav Gupta

Slide 39

Slide 39 text

© 2018 Coding Blocks, Arnav Gupta https://account.codingblocks.com auth_token = xxxx implicit profile page

Slide 40

Slide 40 text

© 2018 Coding Blocks, Arnav Gupta https://api.github.com/profile {header: auth_token = xxxx } profile data fetching in browser profile page name email username

Slide 41

Slide 41 text

© 2018 Coding Blocks, Arnav Gupta https://account.codingblocks.com grant_code = xxxx explicit

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

© 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

Slide 44

Slide 44 text

© 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

Slide 45

Slide 45 text

© 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

Slide 46

Slide 46 text

What we learnt in the process ? © 2018 Coding Blocks, Arnav Gupta

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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 })

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

● 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

Slide 53

Slide 53 text

● 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 …

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

© 2018 Coding Blocks, Arnav Gupta 0-click login

Slide 56

Slide 56 text

© 2018 Coding Blocks, Arnav Gupta 1-click login

Slide 57

Slide 57 text

© 2018 Coding Blocks, Arnav Gupta 2-click login

Slide 58

Slide 58 text

© 2018 Coding Blocks, Arnav Gupta 3-click login

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

© 2018 Coding Blocks, Arnav Gupta

Slide 67

Slide 67 text

© 2018 Coding Blocks, Arnav Gupta

Slide 68

Slide 68 text

We did this too, and ended up frustrated with . . . ● I can’t login…. ● Why? ● I just can’t © 2018 Coding Blocks, Arnav Gupta

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

© 2018 Coding Blocks, Arnav Gupta

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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 ”

Slide 77

Slide 77 text

© 2018 Coding Blocks, Arnav Gupta

Slide 78

Slide 78 text

© 2018 Coding Blocks, Arnav Gupta

Slide 79

Slide 79 text

© 2018 Coding Blocks, Arnav Gupta

Slide 80

Slide 80 text

© 2018 Coding Blocks, Arnav Gupta

Slide 81

Slide 81 text

© 2018 Coding Blocks, Arnav Gupta

Slide 82

Slide 82 text

Inspirations Other similar systems ● StackExchange Network (imo, the best implementation of dual layer SSO) ● Closer home – HasGeek’s lastuser © 2018 Coding Blocks, Arnav Gupta

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

Thank You https://github.com/coding-blocks/oneauth https://account.codingblocks.com @championswimmer © 2018 Coding Blocks, Arnav Gupta