本文将会从最基本的一种web权限验证提及,即HTTP Basic authentication,而后是基于cookies和tokens的权限验证,最后则是signatures和一次性密码。nginx
当客户端发起一个请求时,它可使用HTTP Basic authentication来提供一个用户名和密码,来进行权限验证。git
因为它不依赖于cookies,sessions等任何外部因素,因此它是最简单的权限验证方法。在使用它时,客户端须要在每次请求时,都附带上Authorization
请求头,用户名和密码都不会被加密,可是须要被格式化为如下结构:github
用户名和密码由一个冒号链接,如username:password
web
这个字符串需进行Base64编码算法
Basic
关键字需被放置在这个编码后的字符串的前面浏览器
例子:安全
curl --header "Authorization: Basic am9objpzZWNyZXQ=" my-website.com
在Node.js
中实现它是很是简单的,如下是一个经过Express
中间件来实现的例子:服务器
import basicAuth from 'basic-auth'; function unauthorized(res) { res.set('WWW-Authenticate', 'Basic realm=Authorization Required'); return res.send(401); }; export default function auth(req, res, next) { const {name, pass} = basicAuth(req) || {}; if (!name || !pass) { return unauthorized(res); }; if (name === 'john' && pass === 'secret') { return next(); } return unauthorized(res); };
固然,你也能够在更高层上实现它,如nginx
。cookie
HTTP Basic authentication虽然十分简单,但仍有一些须要注意的地方:session
用户名和密码在每次请求时都会被带上,即便请求是经过安全链接发送的,这也是潜在的可能暴露它们的地方。
若是网站使用的加密方法十分弱,或者被破解,那么用户名和密码将会立刻泄露。
用户经过这种方式进行验证时,并无登出的办法
一样,登录超时也是没有办法作到的,你只能经过修改用户的密码来模拟。
当服务端在响应HTTP请求时,它能够在响应头里加上Set-Cookie
头。而后浏览器会将这个cookie保存起来,并在之后请求同源的地址时,在Cookie
请求头中附上这些cookie。
当使用cookies来进行权限验证时,有如下几点须要注意。
HttpOnly
当设置cookies时,老是使用HttpOnly
标识,这样以来cookies就不能经过document.cookies
获取,用以减小被XSS攻击可能性。
当使用签名cookies时,服务器则能够判断该cookie是否被客户端更改过。
不足:
须要花费额外的功夫来抵御CSRF攻击
与REST风格不匹配。由于它在一个无状态协议里注入了状态。
现今,JWT(JSON Web Token)无处不在。让咱们先来看看它到底长什么样。
JWT由三部分组成:
Header
,由token的类型和哈希算法组成
Payload
,包含了内容主体
Signature
,当你选择HMAC SHA256算法时,它由HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
计算得出。
将你的Koa
应用加上JWT仅需几行代码:
var koa = require('koa'); var jwt = require('koa-jwt'); var app = koa(); app.use(jwt({ secret: 'very-secret' })); // Protected middleware app.use(function *(){ // content of the token will be available on this.state.user this.body = { secret: '42' }; });
例子:
curl --header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" my-website.com
若是你在写提供给原生移动应用或单页web应用的API,JWT是一个不错的选择。
不足:
须要额外的措施来防御XSS攻击
不管是使用cookies仍是token,若是你传输的内容被他人截获,那么它们将能够很容易得假装成真实的用户。
若是解决这个问题?当咱们讨论的是API之间的通讯,而不是浏览器之间的通讯时,有一个办法。
当API的消费者发送一个须要权限验证的请求时,你能够对整个请求用一个私钥进行哈希。你可使用的请求的内容有:
HTTP方法
请求路径
HTTP头
HTTP体
以及一个私钥
API的消费者和提供者都必须持有相同的私钥。在生成了signature
以后,你必须将其加在query string
或HTTP头中。另外,还需附上一个时间戳,用于判断过时。
当这么作时,即便你传输的内容暴露了,攻击者也没法假装成真实用户,由于它没法本身生成signature
。
不足:
不能用于浏览器/客户端中,只能用于API之间的通讯中。
一次性密码算法使用一个共享的密钥和一个当前时间戳或计数器来生成一个一次性密码:
基于时间的一次性密码算法,使用一个当前时间的时间戳
基于HMAC的一次性密码算法,使用一个计数器
这些方法被用于双重认证(two-factor authentication)中:一个用户输入了用户名和密码,而后服务器和客户端同时生成一个一次性密码。
在Node.js
中,使用notp实现它是相对简单的。
不足:
若是共享密钥被窃取,那么用户的token将能够被伪造
若是你只需支持一个web应用,那么cookies和tokens的实现都是能够的(cookies对XSRF的防御较好,而JWT则更易于防御XSS)。
若是你须要同时支持web应用和移动客户端,那么请使用基于token的验证。
若是你正在构建仅与其余API通讯的API,那么就使用signatures。
原文连接:https://blog.risingstack.com/web-authentication-methods-explained/