前后端分离通过Restful API进行数据交互时,如何验证用户的登录信息及权限。在原来的项目中,使用的是最传统也是最简单的方式,前端登录,后端根据用户信息生成一个token,并保存这个 token 和对应的用户id到数据库或Session中,接着把 token 传给用户,存入浏览器 cookie,之后浏览器请求带上这个cookie,后端根据这个cookie值来查询用户,验证是否过期。
但这样做问题就很多,如果我们的页面出现了 XSS 漏洞,由于 cookie 可以被 JavaScript 读取,XSS 漏洞会导致用户 token 泄露,而作为后端识别用户的标识,cookie 的泄露意味着用户信息不再安全。尽管我们通过转义输出内容,使用 CDN 等可以尽量避免 XSS 注入,但谁也不能保证在大型的项目中不会出现这个问题。
在设置 cookie 的时候,其实你还可以设置 httpOnly 以及 secure 项。设置 httpOnly 后 cookie 将不能被 JS 读取,浏览器会自动的把它加在请求的 header 当中,设置 secure 的话,cookie 就只允许通过 HTTPS 传输。secure 选项可以过滤掉一些使用 HTTP 协议的 XSS 注入,但并不能完全阻止。
httpOnly 选项使得 JS 不能读取到 cookie,那么 XSS 注入的问题也基本不用担心了。但设置 httpOnly 就带来了另一个问题,就是很容易的被 XSRF,即跨站请求伪造。当你浏览器开着这个页面的时候,另一个页面可以很容易的跨站请求这个页面的内容。因为 cookie 默认被发了出去。
另外,如果将验证信息保存在数据库中,后端每次都需要根据token查出用户id,这就增加了数据库的查询和存储开销。若把验证信息保存在session中,有加大了服务器端的存储压力。那我们可不可以不要服务器去查询呢?如果我们生成token遵循一定的规律,比如我们使用对称加密算法来加密用户id形成token,那么服务端以后其实只要解密该token就可以知道用户的id是什么了。不过呢,我只是举个例子而已,要是真这么做,只要你的对称加密算法泄露了,其他人可以通过这种加密方式进行伪造token,那么所有用户信息都不再安全了。恩,那用非对称加密算法来做呢,其实现在有个规范就是这样做的,就是我们接下来要介绍的 JWT。
Json Web Token(JWT)
JWT 是一个开放标准(RFC 7519),它定义了一种用于简洁,自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。JWT 可以使用 HMAC 算法或者是 RSA 的公钥密钥对进行签名。它具备两个特点:
简洁(Compact)
可以通过URL, POST 参数或者在 HTTP header 发送,因为数据量小,传输速度快
自包含(Self-contained)
负载中包含了所有用户所需要的信息,避免了多次查询数据库
Header 头部
头部包含了两部分,token 类型和采用的加密算法
Payload 负载
这部分就是我们存放信息的地方了,你可以把用户 ID 等信息放在这里,JWT 规范里面对这部分有进行了比较详细的介绍,常用的由 iss(签发者),exp(过期时间),sub(面向的用户),aud(接收方),iat(签发时间)。
Signature 签名
前面两部分都是使用 Base64 进行编码的,即前端可以解开知道里面的信息。Signature 需要使用编码后的 header 和 payload 以及我们提供的一个密钥,然后使用 header 中指定的签名算法(HS256)进行签名。签名的作用是保证 JWT 没有被篡改过。
三个部分通过.连接在一起就是我们的 JWT 了,它可能长这个样子,长度貌似和你的加密算法和私钥有关系。
首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT。形成的JWT就是一个形同lll.zzz.xxx的字符串。后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage或sessionStorage上,退出登录时前端删除保存的JWT即可。前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题)后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)。验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。
参考 https://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html