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 (And Neither Should You)

133 views

Published on

Remember when setting up an auth system was easy? Me neither. From the signup form, the login form, password reset form, and all the validation in between it can easily take weeks if not months to get something basic up and running. Then you have to deal with all the security considerations. No thanks. During this presentation, the attendees will be introduced to OpenID and OAuth. They will learn how to leverage these technologies to create secure applications, but most importantly, they will learn why and how to delegate authorization and authentication so they can focus on their real work and forget about all that security stuff.

Published in: Internet
  • Be the first to comment

I Don't Care About Security (And Neither Should You)

  1. 1. I Don’t Care About Security And Neither Should You
  2. 2. @joel__lord #SFNode About Me @joel__lord joellord
  3. 3. @joel__lord #midwestjs About Me @joel__lord joellord
  4. 4. @joel__lord #midwestjs OAuth - Flows Authorization Code
  5. 5. @joel__lord #midwestjs OAuth - Flows Authorization Code
  6. 6. @joel__lord #midwestjs OAuth - Flows Authorization Code
  7. 7. That reminds me of OAuth!
  8. 8. @joel__lord #midwestjs OAuth - Flows Authorization Code
  9. 9. @joel__lord #midwestjs OAuth - Flows Authorization Code
  10. 10. @joel__lord #midwestjs OAuth - Flows Authorization Code
  11. 11. @joel__lord #midwestjs OAuth - Flows Authorization Code
  12. 12. @joel__lord #midwestjs OAuth - Flows Authorization Code
  13. 13. @joel__lord #midwestjs OAuth - Flows Authorization Code
  14. 14. But Why?
  15. 15. Delegation!
  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
  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 👍
  21. 21. Traditional Applications ! Browser requests a login page ! The server validates on its database ! It creates a session and provides a cookie identifier
  22. 22. What’s wrong with traditional auth? ! Multiple platforms connecting to your application
  23. 23. What’s wrong with traditional auth? ! Multiple platforms connecting to your application ! Tightly coupled
  24. 24. What’s wrong with traditional auth? ! Multiple platforms connecting to your application ! Tightly coupled ! Sharing credentials to connect to another API
  25. 25. 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
  26. 26. OAuth
  27. 27. OAuth - The Flows Authorization Code
  28. 28. @joel__lord #midwestjs Authentication Flows Authorization Code
  29. 29. @joel__lord #midwestjs Authentication Flows Authorization Code
  30. 30. @joel__lord #midwestjs Authentication Flows Authorization Code
  31. 31. @joel__lord #midwestjs Authentication Flows Authorization Code
  32. 32. @joel__lord #midwestjs Authentication Flows Authorization Code
  33. 33. @joel__lord #midwestjs Authentication Flows Authorization Code
  34. 34. OAuth - The Flows Implicit Flow
  35. 35. @joel__lord #midwestjs Authentication Flows Implicit Flow
  36. 36. @joel__lord #midwestjs Authentication Flows Implicit Flow
  37. 37. @joel__lord #midwestjs Authentication Flows Implicit Flow
  38. 38. @joel__lord #midwestjs Authentication Flows Implicit Flow
  39. 39. @joel__lord #midwestjs Authentication Flows Implicit Flow
  40. 40. @joel__lord #midwestjs Authentication Flows Implicit Flow
  41. 41. Tokens 101
  42. 42. @joel__lord #midwestjs 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
  43. 43. @joel__lord #midwestjs OAuth Tokens Refresh Token ! Enables you to get a new token ! Longed lived ! Can be revoked
  44. 44. @joel__lord #midwestjs OAuth Tokens Refresh Token ! Enables you to get a new token ! Longed lived ! Can be revoked
  45. 45. @joel__lord #midwestjs OAuth Tokens ! WS-Federated ! SAML ! JWT ! Custom stuff ! More…
  46. 46. 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)
  47. 47. JSON Web Token ! Header ! Payload ! Signature Header eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 Payload eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvZWwgTG 9yZCIsImFkbWluIjp0cnVlLCJzY29wZSI6InBvc3RzOnJlY WQgcG9zdHM6d3JpdGUifQ Signature XesR-pKdlscHfUwoKvHnACqfpe2ywJ6t1BJKsq9rEcg
  48. 48. JSON Web Token ! Header ! Payload ! Signature eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMj M0NTY3ODkwIiwibmFtZSI6IkpvZWwgTG9yZCIsImFkbWl uIjp0cnVlLCJzY29wZSI6InBvc3RzOnJlYWQgcG9zdHM6d 3JpdGUifQ.XesR- pKdlscHfUwoKvHnACqfpe2ywJ6t1BJKsq9rEcg
  49. 49. JSON Web Token ! Header ! Payload ! Signature Image: https://jwt.io
  50. 50. Codiiiing Time!
  51. 51. 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); });
  52. 52. @joel__lord #midwestjs Auth Server var express = require('express'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); // ...
  53. 53. @joel__lord #midwestjs Auth Server var express = require('express'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); // ...
  54. 54. @joel__lord #midwestjs Auth Server var express = require('express'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); // ...
  55. 55. @joel__lord #midwestjs Auth Server var express = require('express'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); // ...
  56. 56. @joel__lord #midwestjs Auth Server // Requires ... var users = [ {id: 1, username: "joellord", password: "joellord"}, {id: 2, username: "guest", password: "guest"} ];
  57. 57. @joel__lord #midwestjs 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. @joel__lord #midwestjs 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); });
  59. 59. @joel__lord #midwestjs 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. @joel__lord #midwestjs 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. @joel__lord #midwestjs 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. @joel__lord #midwestjs 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); });
  63. 63. @joel__lord #midwestjs 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"));}
  64. 64. @joel__lord #midwestjs API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  65. 65. @joel__lord #midwestjs API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  66. 66. @joel__lord #midwestjs API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  67. 67. @joel__lord #midwestjs API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  68. 68. @joel__lord #midwestjs API var express = require('express'); var bodyParser = require('body-parser'); var randopeep = require("randopeep"); var expressjwt = require("express-jwt"); var app = express();
  69. 69. @joel__lord #midwestjs API // Requires ... var jwtCheck = expressjwt({ secret: "mysupersecret" });
  70. 70. @joel__lord #midwestjs 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. @joel__lord #midwestjs 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. @joel__lord #midwestjs 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. @joel__lord #midwestjs 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); });
  74. 74. @joel__lord #midwestjs 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"));
  75. 75. @joel__lord #midwestjs Front-End Add the headers
  76. 76. Live Demo https://github.com/joellord/ secure-spa-auth0
  77. 77. Delegation!
  78. 78. Introducing OpenID Connect
  79. 79. @joel__lord #midwestjs 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
  80. 80. @joel__lord #midwestjs OpenID Connect Scopes ! openid ! profile ! email ! address ! phone
  81. 81. @joel__lord #midwestjs OpenID Connect Flows Authorization Code scope=openid%20profile
  82. 82. @joel__lord #midwestjs Authentication Flows Authorization Code
  83. 83. @joel__lord #midwestjs Authentication Flows Authorization Code
  84. 84. @joel__lord #midwestjs Authentication Flows Authorization Code /userinfo
  85. 85. @joel__lord #midwestjs OpenID Connect Full flow https://openidconnect.net
  86. 86. Delegation!
  87. 87. I Don’t Care About Security @joel__lord joellord MidwestJS, Minneapolis, MN August 10, 2018

×