背景
在账号体系里,用户登录后,一般会生成一个加密的token保存在用户端,每次用户端和服务端的交互会带上它,从而服务端可以获取用户的信息,而不需要每次都带上用户的账号+密码。我们称这个token为用户登录态,它其实是用户通过密码(获取手机号+验证码/扫码等方式)换取的一个通行证,这个通行证在一定时间内,可以代表当前用户。
需求
-
安全
- 伪造
当我们费尽心机的保护好用户密码的时候,如果用户的登录态可以被人伪造,我们的工作就会功亏一篑。因为他人可以不通过密码就能制造一个通行证,如同本来我去办理护照是需要带上我个人身份证和其他资料才能办理的,现在有个制假证的,不需要你任何证件,只要知道你的名字,就可以帮你造一本护照出来。
因此,防止被伪造是登录态设计的基本需求。 - 窃取
很多时候,我们会在一些公关网络上网,如果网站没有做类似https等加密的传输,用户端和服务端的请求很容易被截获,而一般登录态会存在cookie中,很容易被别人窃取。同样的,知道你的登录态后,我就可以以你的身份去网站操作了。因此,如何防止被窃取的场景,也是登录态设计的重要安全需求。
- 伪造
失效
登录态失效的场景有:过期、修改密码等。比如用户修改了密码,则之前设备的登录态需要立即失效。用户体验
性能
如果我们设计了一个很复杂的登录态,黑客很难破解,但是可能我们也要花上几秒钟才能解析出来,也是有问题的。账号系统是基础服务,业务都会基于这些服务做功能,如果账号的服务性能有问题,对用户体验是非常大的挑战。互斥
微信只允许一个手机处于活跃状态,而京东却可以用一个账号在两个手机上一起下单。我们今天讨论的是后者的设计方案,允许一个账号同时活跃在两个手机上的场景。要实现微信这样即时通讯类应用需要的互斥性,还有点不一样。
实现
-
核心数据
- TimeStamp:记录创建登录态的时间,用于后续的过期控制。可以精确到毫秒,精确度高,但就是无法通过userId来复现用户使用的登录态。
- UserPlatform:APP和PC的安全性不一样,所以可能对于不同平台的有效期不一样,用这个字段来记录当前平台,会对后续的过期等策略有影响。
- UserIP:记录用户IP,帮助后续判断登录态的使用场景。如,对于pc环境,换了IP后,可能该登录态就自动失效了。
- RandomX:每个用户都有这样的一个值存在服务器端,用户修改密码后,服务端的值随机变化,之前的登录态中的RandomX不再匹配,实现T除登录态的作用。
- 核心数据加密
在登录态的场景中,加密算法一般采用对称加密,如DES/AES等。加密除了输入加密串,还需要一个key和iv,可以将key和iv都取一样的值,也可以采用多组key和iv,多组的场景就需要在登录态中标志下。 -
外层数据
- 版本号:后续方便版本升级
- 签名:为了保证登录态不被篡改和快速验证其有效性,在前面可以加签名。算法自选,用常用的hash算法就可以了。
- 其他:如果在核心数据加密算法中想采用多组Key和IV的场景,在外层数据中需要添加一些其他信息来区分。当然,这样拼接出来的字符都是有意义的,防止泄露过多信息,最后可以将整个串再使用类似base64的算法编码一次。
总结
登录态的设计需要兼顾性能和安全性,本文给到了一种比较常见的设计方案。