Passwordless authentication: Secure, simple, and fast to deploy

【编者按】本文作者为 Florian HeinemannRobert Nyman

Florian 来自 MIT 系统设计与管理学院,专注于复杂的社交技术系统。此前曾在企业软件领域的多家初创公司工作,之后加入 Airbus,担任知识与创新管理经理一职。Robert 是 Mozilla Hacks 技术传道师及编辑。曾就 HTML5,JavaScript 以及 Open Web 发表过多次谈话与博文。Robert 坚定地看好 HTML5 与 Open Web。自1995年就開始在 Front End 开发部门研究 Web 技术。

本文系 OneAPM project师编译呈现,下面为正文。

Passwordless(无密码)是用于 Node.js 程序的一种身份验证中间件。能提高用户安全水平。同一时候具备部署简单、高速的特点。

过去几个月。对热衷于 Web 安全与保密性的人来说。着实激动人心:出现了很多了不起的文章讨论。还有很多事件,都在提高人们的安全意识。

然而,大多数站点仍在使用最早期的 web 身份验证方式:username和password。

虽然username密码这样的身份验证方式的确占领了一席之地。但假设以为这是全部项目的终极选择,我们便应该更加慎重了。我们知道,大多数人在訪问站点时都使用同一套密码

对于那些缺少安全专家支持的 web 项目,假设用户在该站点的密码遭到泄露,那就可能伤及他的 Amazon 账户。我们真的要让用户承担这样的风险么?此外。这样的经典的身份验证机制至少存在两种攻击角度:登录页与密码找回页。并且。后者的实现往往在匆忙中进行。因而风险更高。

近期。我们看到了很多不错的点子

笔者尤其对一个直观并且低技术含量的解决方法感兴趣:一次性密码。这样的方法部署高速。攻击面小,并且不须要 QR codes 或 JavaScript。不管何时,用户想要登录或使之前的会话失效,都能够通过电子邮件或短信息收到一个短时间有效的一次性链接与令牌(token)。假设你想试一试,能够下载passwordless.net中的演示代码。

不幸的是。由于技术栈的区别。基本上不存在现成的解决方式。

因此,Passwordless 针对 Node.js 做出了一些修改。

从 Node.js 与 Express 入手

Passwordless 入门很easy。两个小时以内。你就能学会部署全面且安全的身份验证解决方式:

$ npm install passwordless --save

获取主要的框架。你还要安装某个现成的存储接口,比方 MongoStore,用于安全地存储令牌。

$ npm install passwordless-mongostore --save

在传送令牌给用户时。电子邮件一般是最好的选择(只是。短消息也能够)。

你能够随意选择邮件框架,比方:

$ npm install emailjs --save

基本设置

首先,请求上文用到的全部模块,将它们放在用于初始化 Express 的同一个文件里:

var passwordless = require('passwordless');
var MongoStore = require('passwordless-mongostore');
var email = require("emailjs");

假设你选用 emailjs 进行令牌传递。此时应该与邮箱账户进行连接(比方:Gmail 账户):

var smtpServer  = email.server.connect({
user: yourEmail,
password: yourPwd,
host: yourSmtp,
ssl: true
});

最后的一个预备步骤是告知 Passwordless 你选择了哪一种存储接口。并将之初始化:

// Your MongoDB TokenStore
var pathToMongoDb = 'mongodb://localhost/passwordless-simple-mail';
passwordless.init(new MongoStore(pathToMongoDb));

传递令牌

函数 passwordless.addDelivery(deliver) 会加入新的传送机制。每次须要传送令牌时。就会调用deliver。默认情况下,你选择的机制应该依照下面格式为用户提供链接:

http://www.example.com/token={TOKEN}&uid={UID}

deliver 在调用时。须要全部的细节信息。因此,令牌的传递(在本例中,使用的是 emailjs)例如以下所看到的。相当简单:

passwordless.addDelivery(
function(tokenToSend, uidToSend, recipient, callback) {
var host = 'localhost:3000';
smtpServer.send({
text: 'Hello!nAccess your account here: http://'
+ host + '? token=' + tokenToSend + '&uid='
+ encodeURIComponent(uidToSend),
from: yourEmail,
to: recipient,
subject: 'Token for ' + host
}, function(err, message) {
if(err) {
console.log(err);
}
callback(err);
});
});

初始化 Express 中间件

app.use(passwordless.sessionSupport());
app.use(passwordless.acceptToken({ successRedirect: '/'}));

函数 sessionSupport() 会使登录状态得到保持,因此。用户在浏览站点时才干一直处于登录状态。请确保你已经提前准备好了会话中间件(比方express-session)。

函数 acceptToken() 会截获不论什么外来的令牌,验证用户身份,再将他们重定向至正确的页面。

虽然 successRedirect 选项不是严格要求的。但笔者强烈建议你使用此选项,从而避免合法令牌通过站点向外的 HTTP 链接的 header 来源泄露出去。

路径选择与身份验证

下文默认你已经通过 var router = express.Router(); 配置好路径选择器。

此外,express 文档中也有对应的说明。

你至少须要两个 URLs,从而:

- 展示用于获取用户邮箱地址的页面

- 获取表格细节(通过 POST 方法)

/* GET: login screen */
router.get('/login', function(req, res) {
res.render('login');
});</p> /* POST: login details */
router.post('/sendtoken',
function(req, res, next) {
// TODO: Input validation
},
// Turn the email address into a user ID
passwordless.requestToken(
function(user, delivery, callback) {
// E.g. if you have a User model:
User.findUser(email, function(error, user) {
if(error) {
callback(error.toString());
} else if(user) {
// return the user ID to Passwordless
callback(null, user.id);
} else {
// If the user couldn’t be found: Create it!
// You can also implement a dedicated route
// to e.g. capture more user details
User.createUser(email, '', '',
function(error, user) {
if(error) {
callback(error.toString());
} else {
callback(null, user.id);
}
})
}
})
}),
function(req, res) {
// Success! Tell your users that their token is on its way
res.render('sent');
});

此处有何猫腻?passwordless.requestToken(getUserId) 的任务有二:第一、确保邮箱地址真实存在。第二、将该地址转变为独一无二的用户 ID,通过邮件一并发送,并在之后用于验证用户身份。通常,你都有一套存储用户细节信息的模型,你能够依照上例的说明。进行简单的设置。

在一些情况下(比如。由两个用户编辑过的博客)。你能够跳过用户模型,将他们有效的邮箱地址与其各自的 ID 相联系:

var users = [
{ id: 1, email: 'marc@example.com' },
{ id: 2, email: 'alice@example.com' }
]; /* POST: login details */
router.post('/sendtoken',
passwordless.requestToken(
function(user, delivery, callback) {
for (var i = users.length - 1; i >= 0; i--) {
if(users[i].email === user.toLowerCase()) {
return callback(null, users[i].id);
}
}
callback(null, null);
}),
// Same as above…

HTML 页面

本例仅仅须要一个简单的 HTML 页面,用以获取用户的邮箱地址。

默认情况下,Passwordless 会查找 user 输入栏中的内容:

<html>
<body>
<h1>Login</h1>
<form action="/sendtoken" method="POST">
Email:
<br /><input name="user" type="text">
<br /><input type="submit" value="Login">
</form>
</body>
</html>

保护网页

Passwordless 提供了能确保仅仅有验证用户才干看到指定页面的中间件:

/* Protect a single page */
router.get('/restricted', passwordless.restricted(),
function(req, res) {
// render the secret page
}); /* Protect a path with all its children */
router.use('/admin', passwordless.restricted());

谁处于登录状态?

默认情况下,Passwordless 同意通过请求对象 req.user 获取用户 ID。想要展示或重用此 ID,或从数据库中得到很多其它细节信息,你能够这么实现:

router.get('/admin', passwordless.restricted(),
function(req, res) {
res.render('admin', { user: req.user });
});

或者。更一般化地,你能够加入还有一个中间件,从模型中抽取出某个用户的全部记录,再将其分配给站点中的随意路径:

app.use(function(req, res, next) {
if(req.user) {
User.findById(req.user, function(error, user) {
res.locals.user = user;
next();
});
} else {
next();
}
})

到此为止啦!

以上就是安全地验证用户身份的简单方法。

若想了解很多其它细节,你能够查看深入剖析,从而了解全部的可选项。以及将上述知识整合为一套可行的解决方式的案例。

点评

如前所看到的。全部的身份验证系统都有其优缺点。你应该依照自己的需求进行合理的选择。基于令牌的验证方式,与绝大多数解决方法(包含经典的username/密码方法)一样。都存在一个风险:假设用户的邮箱账户被盗用。并且/或者 SMTP 服务器与用户的连接被入侵,用户在站点的账户就会随之遭到盗用。默认情况下。有两种办法能够减弱该风险(但不是全然避免):短时间有效的令牌以及令牌在使用后自己主动失效。

对大多数站点而言,基于令牌的身份验证方法代表着走向安全的进步:用户无需再想新的密码(这些密码往往很easy)。也不存在用户重用密码的风险。

对于身为开发人员的我们。Passwordless 提供了唯一一种(且相当简单的)身份验证解决方式,该方案易于理解。因此easy保护。此外,我们也无需再处理用户的密码了。

还有一个值得讨论的点是可用性。我们应该同一时候考虑两种情况:用户在站点的首次使用以及兴许的登录。对首次用户而言。基于令牌的身份验证很直观:与经典的登录机制一样,他们还是不得不验证邮箱地址。

可是,在最佳案例中,除此之外就不须要其它细节信息了。不须要再煞费苦心地想一个符合全部限制条件的密码,也不须要刻意记住密码。假设用户再次登录,其体验与特定的用户案例有关。大多数站点的会话有效期都很长,因而不须要再次登录。

或者,用户訪问该站点的频率事实上很低,以致于他们想不起来自己是否已经拥有账户,或者忘记了账户密码。在这样的情况下。Passwordless 在可用性方面的优势相当明显。相同地,这须要经历不多的几个步骤,解释起来也很easy。然而,那些用户訪问频繁的站点。以及/或那些要求用户一周内手动登录几次的站点(比方 Amazon),经典的身份验证(或更保险地:双重验证)也许更加适合。由于用户很可能会真的记住他们的密码,并且意识到好密码的重要性。

虽然 Passwordless 眼下比較稳定,笔者还是很期待你能在 GitHub 留下评论或一些贡献,或者在 Twitter:@thesumofall 上提问笔者。

原文地址:https://hacks.mozilla.org/2014/10/passwordless-authentication-secure-simple-and-fast-to-deploy/

OneAPM 助您轻松锁定

utm_source=Community&utm_medium=Article&utm_term=%E6%97%A0%E5%AF%86%E7%A0%81%E8%BA%AB%E4%BB%BD%E9%AA%8C%E8%AF%81%EF%BC%9A%E5%AE%89%E5%85%A8%E3%80%81%E7%AE%80%E5%8D%95%E4%B8%94%E9%83%A8%E7%BD%B2%E5%BF%AB%E9%80%9F&utm_content=wk404-410&utm_campaign=AiNodejsArti&from=jsclbbrate">Node.js 应用性能瓶颈,通过强大的 Trace 记录逐层分析,直至锁定行级问题代码。以用户角度展示系统响应速度。以地域和浏览器维度统计用户使用情况。

想阅读很多其它技术文章。请訪问 OneAPM 官方博客

本文转自 OneAPM 官方博客

无password身份验证:安全、简单且部署高速的更多相关文章

  1. 教你如何实现微信小程序与.net core应用服务端的无状态身份验证

    随着.net core2的发布,越来越多人使用.net core2开发各种应用服务端,下面我就结合自己最近开发的一款小程序,给大家分享下,怎么使用小程序登录后,小程序与服务端交互的权限控制. .net ...

  2. ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统

    为什么使用 Jwt 最近,移动开发的劲头越来越足,学校搞的各种比赛都需要用手机 APP 来撑场面,所以,作为写后端的,很有必要改进一下以往的基于 Session 的身份认证方式了,理由如下: 移动端经 ...

  3. window10家庭版解决IIS中万维网服务的安全性中无Windows身份验证

    首先在左下角输入cmd搜索->命令提示符->以管理员身份运行->然后复制下面一段命令: dism /online /norestart /add-package:%SystemRoo ...

  4. asp.net 解决IE11下 From身份验证失效问题

    指定如何将 Cookie 用于 Web 应用程序. <forms cookieless="UseCookies" name="test" loginUrl ...

  5. SSH证书登录方式(无password验证登录)

    经常在工作中须要在各个Linux机间进行跳转,每次password的输入成了麻烦,并且也不安全.在实际使用中,在windows下常使用secureCRT工具或teraterm工具进行SSH登录.以及实 ...

  6. ASP.NET Core 项目简单实现身份验证及鉴权

    ASP.NET Core 身份验证及鉴权 目录 项目准备 身份验证 定义基本类型和接口 编写验证处理器 实现用户身份验证 权限鉴定 思路 编写过滤器类及相关接口 实现属性注入 实现用户权限鉴定 测试 ...

  7. 使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)——第1部分

    原文:使用JWT的ASP.NET CORE令牌身份验证和授权(无Cookie)--第1部分 原文链接:https://www.codeproject.com/Articles/5160941/ASP- ...

  8. Web分布式部署,跨应用程序Forms身份验证的集成方案

    最近一个项目要求进行分布式部署.保证在双十一期间系统的正常运行,虽然该系统平时访问量不是很大,但是基于业务需要,必须在至少两台服务器上部署. 该系统需要登录后才可以使用,首先需要解决分布式部署的用户状 ...

  9. cookie小栗子-实现简单的身份验证

    关于Cookie Cookie是一种能够让网站Web服务器把少量数据储存到客户端的硬盘或内存里,或是从客户端的硬盘里读取数据的一种技术. 用来保存客户浏览器请求服务器页面的请求信息,可以在HTTP返回 ...

随机推荐

  1. fullpage.js jq全屏滚动插件

    fullPage.js和fullPage都能实现全屏滚动,二者区别是:fullPage.js需依赖于JQuery库,而fullPage不需要依赖任何一个js库,可以单独使用. (代码演示效果并且可以下 ...

  2. webpack-dev-server坑

    转载人家滴 https://segmentfault.com/q/1010000007561947/a-1020000007596130 需要webpack开发服务(webpack-dev-serve ...

  3. 【C++】各种成员变量

    来自:黄邦勇帅 const 常量对象: 即把对象声明为常量,即 const hyong m,常量对象不能调用可能改变对象的值的函数,因此常量对象只能调用类中的 const 常量函数,因为不是 cons ...

  4. SVN代码提交

    SVN代码提交(转载) 原文链接:http://www.softown.cn/post/100.html 1.SVN代码提交 1) 原则 先更新再提交: SVN是为了多人协同开发而产生的,如果你在提交 ...

  5. shipyard, swarm看到你,我才睡觉:)

    windows下用boot2docker有点不爽,就是网卡识别不好. 还是用纯的virtualbox建centos7虚拟机来搞, 一下就OK. 但记得,要用Iptables来弄墙,去掉firewall ...

  6. APP中常见上下循环滚动通知的简单实现,点击可进入详情

    APP中常见上下循环滚动通知的简单实现,点击可进入详情 关注finddreams博客,一起分享一起进步!http://blog.csdn.net/finddreams/article/details/ ...

  7. SQL 插入多行数据语句整理

     参考别人的,希望对大家有用. 1.只是插入简单的有限行数据时用: insert 要插入的表名(列名1,列名2,....) select '列名1需要的数据','列名2需要的数据',... union ...

  8. 浅谈单页应用和多页应用——Vue.js向

    浅谈单页应用和多页应用--Vue.js向 多页面 多页面应用:每次页面跳转,后台都会返回一个新的HTML文档,就是多页面应用. 在以往传统开发的应用(网站)大多都是多页面应用,路由由后端来写. 页面跳 ...

  9. oracle to_char FM099999

    to_char(column,'FM099999') The FM in the format removes leading and trailing blanks.

  10. 微软应用商店错误 0x00000194

    也可以下载安装包手动更新尝试解决. ------------------------------------------------------------------- 今天OTA升级了1809,应 ...