How Not to Do Authentication in Node.js

How Not to Do Authentication in Node.js

This presentation gives examples of some bad practices when it comes to authentication in and for Node.js applications in general. Furthermore, the interactive code-along includes a way to demonstrate how to fix some of the problems herein contained using tools and methods which are not as complicated as people think.


Shreyansh Pandey

September 30, 2018


  1. Shreyansh Pandey — @acodingpanda How Not to Do Authentication

  2. About Me tl;dr I am pretty boring.

  3. Authentication — What? Why? How?

  4. Bad Ways to do it… MD5, direct-database storage, etc.

  5. MD5? So? “I-can-use-MD5-SHA-etc-because" starter pack: 1. It’s still a one-way

    hash function. 2. It’s secure. It can’t be broken. 3. I enforce strong password rules. 4. I like copying code.
  6. So… How does it matter?

  7. Few pointers: 1. It’s still a one-way hash function. Yes,

    it is. But that does not mean it is secure. 2. It’s secure. It can’t be broken. CVE-2012-3287 — md5crypt (b-crypt means blowfish-crypt).
  8. Do NOT read me: yes, you’re right. I created a

    new slide specifically for this xkcd. I enforce strong password rules.
  9. Discourse in cryptography • Entropy • ROT-3, Caesar’s Cipher (broken?)

    • Paradox?
  10. Buzzword — bcrypt/SHA-* • With SHA, it’s about implementation. FGPA

    or GPU. • SHA has a 32-bit design. • bcrypt is pretty decent at what it does: take more time.
  11. Viś-a-viś, the problem • Consider SHA-256. It’s implemented using a

    32-bit architecture. Very easy on GPU. • bcrypt, not so much. In-memory tables. Iterative recalculation. • GPU in the past, FPGA now. bcrypt can be exploited. • DDoS with bcrypt. Probable.
  12. Then what? • NIST SP-800-132. • Use PBKDF2 with high

    iteration count (Apple uses 10,000.)
  13. New kid on the block • Argon2* family of hashes.

    • One problem Hint: it’s overly complicated to implement.
  14. The Golden Rule It’s impossible to build something absolutely hacker-safe.

    You can make it hacker- deterrent.
  15. Barriers • Cryptography is hard. Without a mathematics degree, it’s

    Greek (literally). • There are some tutorials on how to do credential-storage but they aren’t real world examples. • PBKDF2: Microsoft, 1Password… (also Google?) • Don’t go about building your library*.
  16. The Solution •Try learning Cryptography. It’s not that hard. •Always

    be updated on the latest trends and 0- Day’s. •Don’t follow a tutorial (or a talk) blindly. •If you have some proprietary logic for credential storage, get it audited. •Always remember — in cryptography, you will most certainly need a tailor-made solution.
  17. That’s theory, what about tangible “stuff”? 1. Don’t overdo your

    length. It can lead to a DOS. (*) 2. Use an adaptive one-way function (PBKDF2, bcrypt, Argon2, etc.) with a cost-factor (“time delay”). 3. Use keyed functions like HMAC, etc. in conjunction with (2). 4. Never store plaintext passwords (evidently). 5. The key for HMAC should be treated like a private key; don’t store it in your database.
  18. Right… What about in JavaScript? • There are some really

    cool libraries which take out the guess-work: • libsodium ( • credential ( • node-argon2 (
  19. Viś-a-viś… Most of the credential storage tutorials don’t cover password

    reset… which is a worry.
  20. 1. Predictable tokens A. LCG, pseudo-random number generators, time-based function.

    B. Bruteforce. So, a large entropy? But that doesn’t mean it’s secure. Consider the substitution cipher. 2. Their value. They are as meaningful as passwords; then why are they not stored as such? 3. (Bonus: side-channel verifications. Security questions, rate limiting, audit records.)
  21. Real-World Examples

  22. public function index() { $session = $this->request->session(); $login = $session->read('');

    if(!empty($login)) { return $this->redirect( ['controller' => ‘SecuredAdmin', 'action' => 'dashboard']); } $this->viewBuilder()->layout('admin_login'); $this->set(compact('user')); $this->set('_serialize', ['user']); } function login() { $username = $this->request->data['username']; $password = $this->request->data['password']; $admins = TableRegistry::get('Admins'); $row = $admins ->find() ->where(['username' => $username]) ->where(['password' => md5($password)]) ->first(); ...
  23. None
  24. None
  25. None
  26. None
  27. None
  28. None
  29. const payload = request.payload; if (payload.resettoken != '' && payload.resettoken

    != null) { User().filter({ resettoken: resettoken }).getJoin({ ‘reset’: true }).then(function(err, data) { if (err) { return { isSuccess: false } } return h.view('resetPassword', { resettoken: resettoken }); }) }
  30. app.handle('/', 'post', function(req, h) { User().filter({ resettoken: req.payload.resettoken }).getJoin({ 'reset':

    true }).then(function(err, data) { if (err) { return { isSuccess: false } } User.get({ password: Helpers.calculatehash(password) }).then(function(err, data) { if (err) { return { isSucccess: false } } return { h.view('success-password-' +; } }); }); });
  31. Talk is boring. Show me code.

  32. Sample Application The repository is divided into a couple of

    branches. 1. master — this contains a badly designed Node.js application. 2. better-storage — a better credential storage paradigm. 3. better-auth — a complete RESTful API with auth.

  34. Questions?