Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

I Don't Care About Security

111 views

Published on

Remember that time where setting up a login page was easy? It seems like nowadays, it take many weeks to start a project just to create a signup form, a login form and a forget password screen. And that is if you don’t need 2 factor authentication or passwordless authentication. In a world of security breaches and privacy violations, it is important for developers to understand how modern identity work.

This talk will be in two parts.

For starters, the attendees will be introduced to modern security protocols like OpenID Connect and OAuth. The basics of token authentication will be explained using simple examples that are easy to understand. The concept of tokens will also be explained, more specifically how JWTs work.

In the second part of this presentation, the attendees will learn how to implement their own authentication server, how to secure their APIs and how to protect their Single Page Applications by making use of the protocols described in the first part.

Finally, the presenter will show the participants how to add Auth0 as an authentication server with minimal code changes and will demonstrate the simplicity of using a third party to handle login, signups, lost password as well as 2 factor authentication or passwordless logins.

Published in: Internet
  • Be the first to comment

  • Be the first to like this

I Don't Care About Security

  1. 1. I Don’t Care About Security And Neither Should You
  2. 2. @joel__lord #confoo About Me @joel__lord joellord
  3. 3. @joel__lord #CPL18 OAuth - Flows Authorization Code
  4. 4. @joel__lord #CPL18 OAuth - Flows Authorization Code
  5. 5. @joel__lord #CPL18 OAuth - Flows Authorization Code
  6. 6. That reminds me of OAuth!
  7. 7. @joel__lord #CPL18 OAuth - Flows Authorization Code
  8. 8. @joel__lord #CPL18 OAuth - Flows Authorization Code
  9. 9. @joel__lord #CPL18 OAuth - Flows Authorization Code
  10. 10. @joel__lord #CPL18 OAuth - Flows Authorization Code
  11. 11. @joel__lord #CPL18 OAuth - Flows Authorization Code
  12. 12. @joel__lord #CPL18 OAuth - Flows Authorization Code
  13. 13. But Why?
  14. 14. Delegation!
  15. 15. Traditional Applications ! Browser requests a login page
  16. 16. Traditional Applications ! Browser requests a login page
  17. 17. Traditional Applications ! Browser requests a login page
  18. 18. Traditional Applications ! Browser requests a login page ! The server validates on its database
  19. 19. Traditional Applications ! Browser requests a login page ! The server validates on its database 👍
  20. 20. Traditional Applications ! Browser requests a login page ! The server validates on its database ! It creates a session and provides a cookie identifier
  21. 21. What’s wrong with traditional auth? ! Multiple platforms connecting to your application
  22. 22. What’s wrong with traditional auth? ! Multiple platforms connecting to your application ! Tightly coupled
  23. 23. What’s wrong with traditional auth? ! Multiple platforms connecting to your application ! Tightly coupled ! Sharing credentials to connect to another API
  24. 24. What’s wrong with traditional auth? ! Multiple platforms connecting to your application ! Tightly coupled ! Sharing credentials to connect to another API ! Users have a gazillion passwords to remember, which increases security risks
  25. 25. OAuth
  26. 26. OAuth - The Flows Authorization Code
  27. 27. @joel__lord #CPL18 Authentication Flows Authorization Code
  28. 28. @joel__lord #CPL18 Authentication Flows Authorization Code
  29. 29. @joel__lord #CPL18 Authentication Flows Authorization Code
  30. 30. @joel__lord #CPL18 Authentication Flows Authorization Code
  31. 31. @joel__lord #CPL18 Authentication Flows Authorization Code
  32. 32. @joel__lord #CPL18 Authentication Flows Authorization Code
  33. 33. OAuth - The Flows Implicit Flow
  34. 34. @joel__lord #CPL18 Authentication Flows Implicit Flow
  35. 35. @joel__lord #CPL18 Authentication Flows Implicit Flow
  36. 36. @joel__lord #CPL18 Authentication Flows Implicit Flow
  37. 37. @joel__lord #CPL18 Authentication Flows Implicit Flow
  38. 38. @joel__lord #CPL18 Authentication Flows Implicit Flow
  39. 39. @joel__lord #CPL18 Authentication Flows Implicit Flow
  40. 40. Tokens 101
  41. 41. @joel__lord #CPL18 OAuth Tokens Access Token Refresh Token ! Give you access to a resource ! Controls access to your API ! Short lived ! Enables you to get a new token ! Longed lived ! Can be revoked
  42. 42. @joel__lord #CPL18 OAuth Tokens Refresh Token ! Enables you to get a new token ! Longed lived ! Can be revoked
  43. 43. @joel__lord #CPL18 OAuth Tokens Refresh Token ! Enables you to get a new token ! Longed lived ! Can be revoked
  44. 44. @joel__lord #CPL18 OAuth Tokens ! WS-Federated ! SAML ! JWT ! Custom stuff ! More…
  45. 45. JSON Web Token ! Header ! Payload ! Signature Header { "alg": "HS256", "typ": "JWT" } Payload { "sub": "1234567890", "name": "Joel Lord", "scope": "posts:read posts:write" } Signature HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
  46. 46. JSON Web Token ! Header ! Payload ! Signature Header eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 Payload eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvZWwgTG 9yZCIsImFkbWluIjp0cnVlLCJzY29wZSI6InBvc3RzOnJlY WQgcG9zdHM6d3JpdGUifQ Signature XesR-pKdlscHfUwoKvHnACqfpe2ywJ6t1BJKsq9rEcg
  47. 47. JSON Web Token ! Header ! Payload ! Signature eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMj M0NTY3ODkwIiwibmFtZSI6IkpvZWwgTG9yZCIsImFkbWl uIjp0cnVlLCJzY29wZSI6InBvc3RzOnJlYWQgcG9zdHM6d 3JpdGUifQ.XesR- pKdlscHfUwoKvHnACqfpe2ywJ6t1BJKsq9rEcg
  48. 48. JSON Web Token ! Header ! Payload ! Signature Image: https://jwt.io
  49. 49. Codiiiing Time!
  50. 50. Auth Server API var express = require('express'); var Webtask = require('webtask-tools'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var jwt = require("jsonwebtoken"); var app = express(); var users = [ {id: 1, username: "joellord", password: "joellord"}, {id: 2, username: "guest", password: "guest"} ]; app.use(bodyParser.json()); app.post("/login", function(req, res) { if (!req.body.username || !req.body.password) return res.status(400).send("Need username and password"); var user = users.find(function(u) { return u.username === req.body.username && u.password === req.body.password; }); if (!user) return res.status(401).send("User not found"); var token = jwt.sign({ sub: user.id, scope: "api:read", username: user.username }, "mysupersecret", {expiresIn: "10 minutes"}); res.status(200).send({token: token}); }); app.get('*', function (req, res) { res.sendStatus(404); }); module.exports = Webtask.fromExpress(app); var express = require('express'); var Webtask = require('webtask-tools'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); var users = [ {id: 1, username: "joellord", password: "joellord"}, {id: 2, username: "guest", password: "guest"} ]; app.use(bodyParser.urlencoded()); app.get("/login", function(req, res) { var loginForm = "<form method='post'><input type=hidden name=callback value='" + req.query.callback + "'><input type=text name=username /><input type=text name=password / ><input type=submit></form>"; res.status(200).send(loginForm); }); app.post("/login", function(req, res) { if (!req.body.username || !req.body.password) return res.status(400).send("Need username and password"); var user = users.find(function(u) { return u.username === req.body.username && u.password === req.body.password; }); if (!user) return res.status(401).send("User not found"); var token = jwt.sign({ sub: user.id, scope: "api:read", username: user.username }, "mysupersecret", {expiresIn: "10 minutes"}); res.redirect(req.body.callback + "#access_token=" + token); }); app.get('*', function (req, res) { res.sendStatus(404); });
  51. 51. Auth Server var express = require('express'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); // ...
  52. 52. Auth Server var express = require('express'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); // ...
  53. 53. Auth Server var express = require('express'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); // ...
  54. 54. Auth Server var express = require('express'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); // ...
  55. 55. Auth Server // Requires ... var users = [ {id: 1, username: "joellord", password: "joellord"}, {id: 2, username: "guest", password: "guest"} ];
  56. 56. Auth Server // Requires ... var users = [...]; app.use(bodyParser.urlencoded()); app.post("/login", function(req, res) { // POST for login }); app.get('*', function (req, res) { res.sendStatus(404); });
  57. 57. Auth Server // Requires ... var users = [...]; app.use(bodyParser.urlencoded()); app.post("/login", function(req, res) { // POST for login }); app.get('*', function (req, res) { res.sendStatus(404); });
  58. 58. Auth Server app.post("/login", function(req, res) { // POST for login if (!req.body.username || !req.body.password) return res.status(400).send("Need username and password"); var user = users.find(function(u) { return u.username === req.body.username && u.password === req.body.password; }); if (!user) return res.status(401).send("User not found"); var token = jwt.sign({ sub: user.id, scope: "api:read", username: user.username }, "mysupersecret", {expiresIn: "10 minutes"}); res.redirect(req.body.callback + "#access_token=" + token); });
  59. 59. Auth Server app.post("/login", function(req, res) { // POST for login if (!req.body.username || !req.body.password) return res.status(400).send("Need username and password"); var user = users.find(function(u) { return u.username === req.body.username && u.password === req.body.password; }); if (!user) return res.status(401).send("User not found"); var token = jwt.sign({ sub: user.id, scope: "api:read", username: user.username }, "mysupersecret", {expiresIn: "10 minutes"}); res.redirect(req.body.callback + "#access_token=" + token); });
  60. 60. Auth Server app.post("/login", function(req, res) { // POST for login if (!req.body.username || !req.body.password) return res.status(400).send("Need username and password"); var user = users.find(function(u) { return u.username === req.body.username && u.password === req.body.password; }); if (!user) return res.status(401).send("User not found"); var token = jwt.sign({ sub: user.id, scope: "api:read", username: user.username }, "mysupersecret", {expiresIn: "10 minutes"}); res.redirect(req.body.callback + "#access_token=" + token); });
  61. 61. Auth Server app.post("/login", function(req, res) { // POST for login if (!req.body.username || !req.body.password) return res.status(400).send("Need username and password"); var user = users.find(function(u) { return u.username === req.body.username && u.password === req.body.password; }); if (!user) return res.status(401).send("User not found"); var token = jwt.sign({ sub: user.id, scope: "api:read", username: user.username }, "mysupersecret", {expiresIn: "10 minutes"}); res.redirect(req.body.callback + "#access_token=" + token); });
  62. 62. Auth Server // Requires ... var users = [...]; app.use(bodyParser.urlencoded()); app.post("/login", function(req, res) { // POST for login }); app.get('*', function (req, res) { res.sendStatus(404); }); app.listen(8080, () => console.log("Auth server running on 8080"));}
  63. 63. API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  64. 64. API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  65. 65. API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  66. 66. API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  67. 67. API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  68. 68. API // Requires ... var jwtCheck = expressjwt({ secret: "mysupersecret" });
  69. 69. API // Requires and config ... app.get("/headline", function(req, res) { // Unprotected res.status(200).send(randopeep.clickbait.headline()); }); app.get("/protected/headline", jwtCheck, function(req, res) { // Protected res.status(200).send(randopeep.clickbait.headline("Joel Lord")); }); app.get('*', function (req, res) { res.sendStatus(404); });
  70. 70. API // Requires and config ... app.get("/headline", function(req, res) { // Unprotected res.status(200).send(randopeep.clickbait.headline()); }); app.get("/protected/headline", jwtCheck, function(req, res) { // Protected res.status(200).send(randopeep.clickbait.headline("Joel Lord")); }); app.get('*', function (req, res) { res.sendStatus(404); });
  71. 71. API // Requires and config ... app.get("/headline", function(req, res) { // Unprotected res.status(200).send(randopeep.clickbait.headline()); }); app.get("/protected/headline", jwtCheck, function(req, res) { // Protected res.status(200).send(randopeep.clickbait.headline("Joel Lord")); }); app.get('*', function (req, res) { res.sendStatus(404); });
  72. 72. API // Requires and config ... app.get("/headline", function(req, res) { // Unprotected res.status(200).send(randopeep.clickbait.headline()); }); app.get("/protected/headline", jwtCheck, function(req, res) { // Protected res.status(200).send(randopeep.clickbait.headline("Joel Lord")); }); app.get('*', function (req, res) { res.sendStatus(404); });
  73. 73. API // Requires and config ... app.get("/headline", function(req, res) { // Unprotected }); app.get("/protected/headline", jwtCheck, function(req, res) { // Protected }); app.get('*', function (req, res) { res.sendStatus(404); }); app.listen(8888, () => console.log("API listening on 8888"));
  74. 74. @joel__lord #CPL18 Front-End Add the headers
  75. 75. Live Demo github.com/joellord/idontcare
  76. 76. Delegation!
  77. 77. Introducing OpenID Connect
  78. 78. @joel__lord #CPL18 OpenID Connect ! Built on top of OAuth 2.0 ! OpenID Connect (OIDC) is to OpenID what Javascript is to Java ! Provides Identity Tokens in JWT format ! Uses a /userinfo endpoint to provide the info
  79. 79. @joel__lord #CPL18 OpenID Connect Scopes ! openid ! profile ! email ! address ! phone
  80. 80. @joel__lord #CPL18 OpenID Connect Flows Authorization Code scope=openid%20profile
  81. 81. @joel__lord #CPL18 Authentication Flows Authorization Code
  82. 82. @joel__lord #CPL18 Authentication Flows Authorization Code
  83. 83. @joel__lord #CPL18 Authentication Flows Authorization Code /userinfo
  84. 84. @joel__lord #CPL18 OpenID Connect Full flow https://openidconnect.net
  85. 85. Delegation!
  86. 86. I Don’t Care About Security JS-Paris, April 6th 2018 @joel__lord joellord

×