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)

32 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

  • Be the first to like this

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 #CoderCruise About Me @joel__lord joellord
  3. 3. @joel__lord #CoderCruise OAuth - Flows Authorization Code
  4. 4. @joel__lord #CoderCruise OAuth - Flows Authorization Code
  5. 5. @joel__lord #CoderCruise OAuth - Flows Authorization Code
  6. 6. That reminds me of OAuth!
  7. 7. @joel__lord #CoderCruise OAuth - Flows Authorization Code
  8. 8. @joel__lord #CoderCruise OAuth - Flows Authorization Code
  9. 9. @joel__lord #CoderCruise OAuth - Flows Authorization Code
  10. 10. @joel__lord #CoderCruise OAuth - Flows Authorization Code
  11. 11. @joel__lord #CoderCruise OAuth - Flows Authorization Code
  12. 12. @joel__lord #CoderCruise 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 #CoderCruise Authentication Flows Authorization Code
  28. 28. @joel__lord #CoderCruise Authentication Flows Authorization Code
  29. 29. @joel__lord #CoderCruise Authentication Flows Authorization Code
  30. 30. @joel__lord #CoderCruise Authentication Flows Authorization Code
  31. 31. @joel__lord #CoderCruise Authentication Flows Authorization Code
  32. 32. @joel__lord #CoderCruise Authentication Flows Authorization Code
  33. 33. OAuth - The Flows Implicit Flow
  34. 34. @joel__lord #CoderCruise Authentication Flows Implicit Flow
  35. 35. @joel__lord #CoderCruise Authentication Flows Implicit Flow
  36. 36. @joel__lord #CoderCruise Authentication Flows Implicit Flow
  37. 37. @joel__lord #CoderCruise Authentication Flows Implicit Flow
  38. 38. @joel__lord #CoderCruise Authentication Flows Implicit Flow
  39. 39. @joel__lord #CoderCruise Authentication Flows Implicit Flow
  40. 40. Tokens 101
  41. 41. @joel__lord #CoderCruise 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 #CoderCruise OAuth Tokens Refresh Token ! Enables you to get a new token ! Longed lived ! Can be revoked
  43. 43. @joel__lord #CoderCruise OAuth Tokens Refresh Token ! Enables you to get a new token ! Longed lived ! Can be revoked
  44. 44. @joel__lord #CoderCruise 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. @joel__lord #midwestjs Auth Server var express = require('express'); var bodyParser = require('body-parser'); var jwt = require("jsonwebtoken"); var app = express(); // ...
  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 // Requires ... var users = [ {id: 1, username: "joellord", password: "joellord"}, {id: 2, username: "guest", password: "guest"} ];
  56. 56. @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); });
  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 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. @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 // 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. @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();
  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 // Requires ... var jwtCheck = expressjwt({ secret: "mysupersecret" });
  69. 69. @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); });
  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 }); 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 #CoderCruise Front-End Add the headers
  75. 75. Live Demo https://github.com/joellord/ secure-spa-auth0
  76. 76. Delegation!
  77. 77. Introducing OpenID Connect
  78. 78. @joel__lord #CoderCruise 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 #CoderCruise OpenID Connect Scopes ! openid ! profile ! email ! address ! phone
  80. 80. @joel__lord #CoderCruise OpenID Connect Flows Authorization Code scope=openid%20profile
  81. 81. @joel__lord #CoderCruise Authentication Flows Authorization Code
  82. 82. @joel__lord #CoderCruise Authentication Flows Authorization Code
  83. 83. @joel__lord #CoderCruise Authentication Flows Authorization Code /userinfo
  84. 84. @joel__lord #CoderCruise OpenID Connect Full flow https://openidconnect.net
  85. 85. @joel__lord #CoderCruise OpenID Connect In Action
  86. 86. Delegation!
  87. 87. I Don’t Care About Security @joel__lord joellord CoderCruise, The Bahamas September 1st, 2018

×