Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

Authenticating and Securing Node.js APIs

4 908 vues

Publié le

In this talk, Shubhra Kar from StrongLoop will cover best practices for securing APIs. He'll give an overview of how to integrate Passport, oAuth and social logins into your Node app. Also, presented will be user and login management, SSL termination, rate limiting and throttling plus reverse proxy.

Publié dans : Logiciels
  • Soyez le premier à commenter

Authenticating and Securing Node.js APIs

  1. 1. Shubhra Kar | Products & Education twitter:@shubhrakar {“Node.js”: “APIs @hyperscale”}
  2. 2. SSL – Setup in Loopback.io $ openssl genrsa -out privatekey.pem 1024 $ openssl req -new -key privatekey.pem -out certrequest.csr $ openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem var path = require('path'), fs = require("fs"); exports.privateKey = fs.readFileSync(path.join(__dirname, './private/privatekey.pem')).toString(); exports.certificate = fs.readFileSync(path.join(__dirname, './private/certificate.pem')).toString();
  3. 3. SSL – App Usage in Loopback.io var https = require('https'); var sslConfig = require('./ssl-config'); ... var options = { key: sslConfig.privateKey, cert: sslConfig.certificate }; … server.listen(app.get('port'), function() { var baseUrl = (httpOnly? 'http://' : 'https://') + app.get('host') + ':' + app.get('port'); app.emit('started', baseUrl); console.log('LoopBack server listening @ %s%s', baseUrl, '/'); }); return server;
  4. 4. ACL in Loopback.io READ: exists - Boolean method that determines whether a user exists. findById - Find a user by ID. find - Find all users that match specified conditions. findOne - Finds a single user instance that matches specified conditions. count - Returns the number of users that match the specified conditions. WRITE: create - create a new user. updateAttributes (update) - update a user record. upsert (update or insert) - update or insert a new user record. destroyById (equivalent to removeById or deleteById) - delete the user with the specified ID. For other methods, the default access type is EXECUTE; for example, a custom method maps to the EXECUTE access type.
  5. 5. Full Stack (MEAN App Angular frontend)
  6. 6. Full Stack (Loopback backend API)
  7. 7. Full Stack (Loopback backend API Authorization)
  8. 8. Static Roles in Loopback.io User.create([ {username: 'John', email: 'john@doe.com', password: 'opensesame'}, {username: 'Jane', email: 'jane@doe.com', password: 'opensesame'}, {username: 'Bob', email: 'bob@projects.com', password: 'opensesame'} ], function(err, users) { if (err) return cb(err); //create the admin role Role.create({ name: 'admin' }, function(err, role) { if (err) cb(err); //make bob an admin role.principals.create({ principalType: RoleMapping.USER, principalId: users[2].id }, function(err, principal) { cb(err); }); }); });
  9. 9. Mapping Roles to ACLs { "accessType": "EXECUTE", "principalType": "ROLE", "principalId": "admin", "permission": "ALLOW", "property": "find" }
  10. 10. Built in dynamic roles in Loopback.io
  11. 11. Built in dynamic roles in Loopback.io module.exports = function(app) { var Role = app.models.Role; Role.registerResolver('teamMember', function(role, context, cb) { function reject(err) { if(err) { return cb(err); } cb(null, false); } if (context.modelName !== 'project') { // the target model is not project return reject(); } var userId = context.accessToken.userId; if (!userId) { return reject(); // do not allow anonymous users }
  12. 12. Built in dynamic roles in Loopback.io // check if userId is in team table for the given project id context.model.findById(context.modelId, function(err, project) { if(err || !project) { reject(err); } var Team = app.models.Team; Team.count({ ownerId: project.ownerId, memberId: userId }, function(err, count) { if (err) { return reject(err); } cb(null, count > 0); // true = is a team member }); }); }); };
  13. 13. Mapping Dynamic Role to ACLs. { "accessType": "READ", "principalType": "ROLE", "principalId": "teamMember", "permission": "ALLOW", "property": "findById" }
  14. 14. OAuth2.0 and JWT in Loopback.io
  15. 15. Setup – OAuth 2.0 in Loopback.io npm install loopback-component-oauth2
  16. 16. Configuration – OAuth2.0 in Loopback.io var oauth2 = require('loopback-component-oauth2'); var options = { dataSource: app.dataSources.db, // Data source for oAuth2 metadata persistence loginPage: '/login', // The login page URL loginPath: '/login' // The login form processing URL }; oauth2.oAuth2Provider( app, // The app instance options // The options ); oauth2.authenticate(['/protected', '/api', '/me'], {session: false, scope: 'email'})
  17. 17. 3rd Party Logins using Passport strategies
  18. 18. Setup of passport component in Loopback.io npm install loopback-component-passport
  19. 19. Config – Facebook Authentication in Loopback.io { "facebook-login": { "provider": "facebook", "module": "passport-facebook", "clientID": "{facebook-client-id-1}", "clientSecret": "{facebook-client-secret-1}", "callbackURL": "http://localhost:3000/auth/facebook /callback", "authPath": "/auth/facebook", "callbackPath": "/auth/facebook/callback", "successRedirect": "/auth/account", "scope": ["email"] }
  20. 20. Config – Google Authentication in Loopback.io { "google-link": { "provider": "google", "module": "passport-google-oauth", "strategy": "OAuth2Strategy", "clientID": "{google-client-id-2}", "clientSecret": "{google-client-secret-2}", "callbackURL": "http://localhost:3000/link/google/ callback", "authPath": "/link/google", "callbackPath": "/link/google/callback", "successRedirect": "/link/account", "scope": ["email", "profile"], "link": true }
  21. 21. Config – MS AD Authentication in Loopback.io { "ms-ad": { "provider": "ms-ad", "authScheme":"ldap", "module": "passport-ldapauth", "authPath": "/auth/msad", "successRedirect": "/auth/account", "failureRedirect": "/msad", "failureFlash": true, "session": true, "LdapAttributeForLogin": "mail", "LdapAttributeForUsername": "mail", "LdapAttributeForMail": "mail", "server":{ "url": "ldap://ldap.example.org:389/dc=example,dc=org", "bindDn": "bindUsername", "bindCredentials": "bindPassword", "searchBase": "ou=people,dc=example,dc=org", "searchAttributes": ["cn", "mail", "uid", "givenname"], "searchFilter": "(&(objectcategory=person)(objectclass=user)(|(s amaccountname={{username}})(mail={{username}})))" } }
  22. 22. Application Level passport configurator in Loopback // Create an instance of PassportConfigurator with the app instance var PassportConfigurator = require('loopback-component- passport').PassportConfigurator; var passportConfigurator = new PassportConfigurator(app); app.boot(__dirname); ... // Enable http session app.use(loopback.session({ secret: 'keyboard cat' })); // Load the provider configurations var config = {}; try { config = require('./providers.json'); } catch(err) { console.error('Please configure your passport strategy in `providers.json`.'); console.error('Copy `providers.json.template` to `providers.json` and replace the clientID/clientSecret values with your own.'); process.exit(1); }
  23. 23. Application Level using Passport configurator // Initialize passport passportConfigurator.init(); // Set up related models passportConfigurator.setupModels({ userModel: app.models.user, userIdentityModel: app.models.userIdentity, userCredentialModel: app.models.userCredential }); // Configure passport strategies for third party auth providers for(var s in config) { var c = config[s]; c.session = c.session !== false; passportConfigurator.configureProvider(s, c); }
  24. 24. Synchronous API “Re-Composition” is an anti-pattern
  25. 25. Security & Social Logins Loopback async API Gateway*
  26. 26. Micro services scaling
  27. 27. Hyper-scale & Micro-services Deployment

×