5.用户安全架构设计(二)
5.6 5种用户注册设计
注册是每个封闭式系统都需要的功能,属于一种数据采集手段,采集的数据作为用户登录及数据关联的基础。为了保证注册的真实性,往往需要用户身份的验证和账户的激活流程。在这些注册流程中,最重要的就是保证用户信息的安全和激活验证码的安全。
注册可以分为开放式注册、封闭式注册、半封闭式注册、手机验证码注册和邮箱激活注册,每一种注册方式均有不同的设计方法。
5.6.1 开放式注册、封闭式注册和半封闭式注册
1.开放式注册和封闭式注册
开放式注册是将注册功能暴露给用户,用户可以自己填写必要信息,完成注册、激活、登录。而封闭式注册则没有用户注册页面,只能由管理员在后台添加。
对于2B、2C的互联网产品,绝大多数都采用开放式注册或第三方登录注册的方式。对于企业内部系统,绝大多数都采取封闭式注册的方式。
2.半封闭式注册
现状:有些企业员工申请系统账号是这样操作的,员工填写Excel申请表,然后用邮件发送给管理员,管理员收到申请后核实信息,核对无误后再一个个录入系统,或者导入系统,最终把生成的账号和密码再用邮件发送给员工。
问题:流程烦琐,如果用户信息填写不正确,就要反复沟通调整;管理员不断地进行重复劳动;密码不是员工自己设置的,管理员完全掌握,以邮件或其他方式传递密码都十分不安全。
方案:将封闭式注册加上互联网思维,变为半自助化的用户注册功能。半封闭式注册流程如图5-17所示,包含以下5个步骤。
(1)员工线上填写注册申请信息,如姓名、证件号、员工号、所在部门、职位、邮箱、手机号、密码等企业要求的信息,然后提交申请。
(2)服务端接收到申请后,存储注册信息,并将用户状态标记为未激活,等待管理员审核。
(3)向客户端返回申请成功,请等待审核的应答消息。
(4)管理员核对员工信息,如果信息无误,则审核通过,并将用户状态修改为已激活。
(5)向用户发送通知短信或邮件,告知用户已开通。
通过这种半封闭式注册的方式申请系统账号,大大提高了账户开通的效率和安全性,没有用户密码泄露的风险,同时满足了企业的管理要求。传统软件普遍缺乏互联网化的思考,将线下操作和线上流程做有机的整合,一些简单的思维变通就是创新,就能够提高生产率。
思考1:如果管理员审核不通过,则可以作废原有注册信息,然后通知用户重新填写注册信息,再次申请注册。这种设计只适用于用户需要填写的信息较少的情况。如果用户需要填写的信息较多,则让用户全部重新录入一遍,显然是不合理的。可以在提醒短信或邮件中,将信息修改URL发送给用户。例如,http://xxx:xx/applyReg?id=1q4s7d9v在URL中携带id参数,为本次申请的唯一ID。
这样,在用户打开链接后,就可以根据申请ID,从服务端获得当时填写的信息,并在此基础之上进行修改,节省了用户的录入成本,如图5-18所示。在这个设计中,有以下3个数据安全问题很容易被忽略。
(1)对于申请ID的设计不可以是1、2、3这种自增主键,或者是纯数字主键,一旦用户获取此链接,随意修改一下ID的数值就可能查询到其他人的申请记录,造成数据泄露。
例如,原链接http://xxx:xx/applyReg?id=1修改为http://xxx:xx/applyReg?id=2,就可以获取申请ID为2的全部数据。因此,URL上携带的申请ID必须为MD5、SHA加工过的字符串,或者是UUID字符串,保证唯一性,又保证了防篡改性。
(2)第6步服务端使用申请ID去查询原申请信息时,一定要加上状态控制,只允许查询审核不通过状态的数据,否则用户可以反复利用此链接修改用户数据。
(3)第8步用户再次提交申请,服务端也要增加状态判断,只有当前状态为审核未通过状态的数据才允许再次申请,并且将状态再次修改为待审核状态。
思考2:半封闭式注册设计一般只适合内部管理系统,而不适合互联网产品,否则很容易被攻击,造成大量的垃圾注册信息。如果需要将此流程开放到互联网上,则必须在员工提交信息之前增加手机验证码、邮箱验证、图片验证码等手段进行人机识别,从而防止恶意攻击。
5.6.2 手机验证码注册
国外大多数的应用都是采用邮箱注册的,而中国大多数的应用都是采用手机号注册的,所以如果开发的系统涉及国际化推广,则一定不要忽略这个细节。国外互联网发展得较早,那时手机还不是那么方便,并且短信发送的成本很高。所以,国外系统从一开始就使用邮箱与用户建立连接,从而沿用了这种使用习惯。
而国内互联网起步较晚,大多数人都没有邮箱,所以早期国内采用账号加密码注册的方式最多。随着手机的普及,现在国内几乎每个人都有一个手机号,而邮箱的使用率却非常低,这也是为什么从邮箱注册跨越到了手机注册的原因。
使用手机验证码注册有哪些优势?
手机号与人存在真实的绑定关系,由于手机号在国内采用实名制,因此信息造假的可能性极低,对于用户的后期营销和活动推广会十分有利。但是,也因为这个原因,有些用户害怕泄露自己的隐私,抵触使用手机号注册。
相比邮箱而言,手机短信能够更加快速地触达用户,而邮箱必须使用指定软件,然后登录查看。手机验证码机制能够保证注册人就是手机号持有者,更好地防止了恶意注册。
手机验证码注册设计这里不再赘述,详情可参见4.3.1小节。
5.6.3 邮箱激活注册
邮箱激活注册是PC端系统经常使用的方式,流程如图5-19所示。
(1)客户端填写注册邮箱、账户密码等信息。
(2)提交已经填写的信息给服务端。
(3)服务端校验邮箱是否已经注册,如果没有注册,则生成账户信息,状态设置为待激活。同时,发送激活邮件到用户的注册邮箱,邮箱的内容最主要的就是激活链接,如http://xxxx.xx/active?token=1ajduw82je&email=ikvcjdiwjk839xdi1。激活链接中包含本次激活的Token加密串和要激活的邮箱加密串,Token的使用原理可参见5.4节。
(4)用户登录邮箱,打开激活链接,将Token、邮箱发送至服务端,发起激活操作。
(5)服务端验证Token与邮箱是否匹配,以及Token是否有效,然后激活用户。
(6)服务端返回账号激活成功消息。
手机验证码注册是先验证,再将账户数据落地,相当于是一次性申请和开通。而邮箱激活注册是先留存用户数据,再修改用户的状态。因此,邮箱激活注册更容易造成垃圾注册数据。
5.7 RBAC用户权限设计
用户权限是指用户完成身份认证,成功登录系统后能做什么,能使用哪些功能。这也是几乎所有企业系统都必须具备的功能。开放式的互联网系统中所有普通用户的权限都是相同的,只有当用户等级不同时,才会在基础功能之上提供区别于普通用户的增值功能。
企业系统主要采用RBAC权限模型进行权限设计。RBAC可以演化出用户角色权限模型、继承模型、用户组模型、权限组模型等。
5.7.1 RBAC权限模型
RBAC(Role Based Access Control,基于角色的访问控制)是业界使用较多的权限模型,它较好地解决了用户与权限之间的耦合性问题。
例如,现有表5-6所示的系统权限需要分配,应该如何设计呢?
在不使用RBAC的情况下,直接将权限分配给用户,情况会变得非常复杂,每个人都会有很多的权限,关系如图 5-20所示。如果一个系统有成千上万个用户,那么将变得不可想象,简直就是一张蜘蛛网,对系统管理人员也会造成巨大的困扰。
在用户与权限之间增加角色的概念,就形成了RBAC的基础模型—用户角色权限模型(图5-21),以此达到了解耦的目的,这也是架构师经常采用的分层设计原理。用户角色权限模型也是应用最广、最基础的权限模型。
引入RBAC模型之后,权限都分配在角色上,再将角色与用户关联,如此使 用户权限的分配变得十分清晰。
1.权限的分类和区别
权限包含页面权限、操作权限和数据权限,每一层权限都是递进关系,从而形成树结构,设计者必须要厘清三者所包含的内容,如图5-23所示。
(1)页面权限:一般是指页面或菜单权限,它处于权限的最顶层,一般是其他权限获取的先决条件,通常采用控制用户是否可以看到某个页面或菜单来控制访问权限。例如,普通员工只能看到报销系统中的申请记录、办理进度等基本菜单,而看不到财务转账、财务报表等菜单。
(2)操作权限:是指增、删、改、查权限,一般通过页面中的按钮、热点区域和某些事件触发。控制方式主要有两种:一种是用户可以看到,但是不一定可以操作,如禁用按钮或在用户点击按钮时返回错误提示;另一种是让用户看不到,不同权限的人进入同一个功能页面,看到的内容是不同的。例如,作为部门负责人、财务主管,都可以使用收支明细账管理功能,但是部门负责人只能看,不能改,而财务主管既可以看,也可以改。
(3)数据权限:是指数据的可见范围和可操作范围,属于操作权限的下一层能级。例如,同样的员工信息表,有些人可以看到工资栏,有些人却看不到。用户只可以查看自己的订单,而不可以查看其他人的订单。
2.权限控制原则
页面权限控制优先于操作权限控制,操作权限控制优先于数据权限控制。那是不是意味着做好了页面权限和操作权限就不需要考虑数据权限了呢?
例如,订单查询RESTful接口http://xxx:xx/order/id是根据id查询订单的详细信息。只要更换id参数,就可以查询任意订单信息,就算不属于自己的订单也可以查,这样就造成了数据泄露。
因此,只在表面上做安全控制是远远不够的。
3.关系型数据库设计
如图5-24所示,用户与角色为多对多关系,一个用户可以有多个角色,一个角色也可以授权给多个用户。角色与权限也为多对多关系,一个角色可以有多个权限,一个权限也可以分配给多个角色。
5.7.2 RBAC权限继承
虽然RBAC权限模型可以简化用户和权限之间的配置复杂度,但是依然会面临一些问题。例如,有这样一个需求,普通用户只具有修改密码、修改手机号等基础权限;初级财务人员不仅具有普通用户权限,还具有制作工资单权限;中级财务人员具有初级财务人员的全部权限,同时具有工资单审核权限、转账申请权限;高级财务人员具有中级财务人员的全部权限,同时具有转账审批权限。
如果使用图5-26这种用户角色权限模型,则授权模型如图5-27所示。每种角色都要重复勾选很多的权限,大量的权限交叉,当公司内的岗位、职责很多,或者相同的岗位只是权限存在细微差别时,就要重新创建一个角色,并且把所有权限重新分配给它。长此以往,系统内的角色越来越多,最极端的情况就是,每个用户都对应一个角色。
当然,可以采用一个用户授予多个角色的方式来完成,可以将用户同时授予普通用户、初级财务、中级财务和高级财务4个角色,但是并不能很好地解决这个问题。
仔细分析一下,在本需求中角色之间是存在继承关系的,高级职位所具有的权限包含低级职位所具有的权限,即高级职位继承了低级职位。利用继承关系,可以进一步简化授权复杂度,如图5-28所示。
继承模式需要维护角色之间的继承关系,以便于找到某个角色所具有的全部权限,从而增加了系统的实现难度。例如,要不断地找到高级财务角色的父节点,父节点的父节点,以此类推,并且将每个父节点的权限进行叠加。
这种方式固然简化了管理员的维护成本,也建立起了角色之间的关系,但是却增加了系统的复杂度。此种结构适用于公司管理组织架构简单清晰、职责交叉度较低的企业。
应该尽量避免出现多继承,以免角色关系混乱,难以控制,如图5-30所示。
角色A继承自角色B、C,而角色C又继承自角色E、D,当角色特别多时,就会出现混乱,数据关系复杂,管理员无法管理。因此,继承模型应该尽量采用单继承的模式,这适合组织架构以树结构为主的场景,最终应该形成一棵单继承树,如图5-31所示。
注意
没有完美通用的设计,指望使用一套模型适用于所有场景是很难实现的。所以,架构设计的原则是以业务为驱动,去寻找满足业务场景的最佳设计。
5.7.3 RBAC权限模型演进
对于RBAC权限模型还可以做一些改进,但是这些改进完全取决于公司内的用户数量和角色数量。
1.用户组模型
图 5-32所示的用户组模型,适用于经常要把多个角色授权给一类用户的情况,或者为同一批人增加相同角色的情况。例如,新入职的每个后端开发人员都要授予普通用户、文档管理、代码管理、后端开发和数据库管理4个角色,每个用户都要选择4个角色就很麻烦。
2.权限组模型
图5-35所示的权限组模型与用户组模型原理相同,主要是为了解决权限过多、需要反复授权的情况。 因此,抽象出一层权限组,作为角色与权限之间的纽带。
5.8 互联网权限架构设计
随着分布式架构的占有率逐年攀升,无论是传统企业还是互联网企业,现在都在构建自己的分布式微服务架构体系。传统的基于Session的权限控制存在共享、内存占用过高等问题,因此现在普遍采用基于Token的轻量化解决方案,对于分布式系统具有良好的支持。
这涉及Token的生成、发放、有效期、刷新、延期等事件。Token的使用根据不同的场景可以有很多种变化,包含基于Token的访问控制、SecretID和SecretKey模式、JWT模式等多种设计方案。
5.8.1 基于Token的访问控制
有状态接口设计会导致程序必须要考虑到Session的存储、迁移、共享问题,所以最适合弹性伸缩的设计为无状态接口设计。注意无状态接口并不是说所有接口都不需要登录就可以访问,那样系统将完全暴露在危险之中。
1.基于Token(令牌)的无状态接口设计
名词解释如下。
(1)认证服务:持有用户的信息,可以比对用户名和密码的服务。用于发放、验证、查询、删除和刷新Token的服务。
(2)资源服务:完成真正的业务处理的服务,如订单服务、支付服务等。
基于Token的访问控制流程如图 5-37所示。
(1)客户端请求授权(登录),提交用户名、密码和客户端标识。客户端标识就是代表客户端身份的证明。例如,用户不可以直接发送请求去调用某银行的登录接口,必须使用银行自己的App才可以调用,因为客户端必须是银行服务器认可的客户端。
(2)认证授权中心校验用户名、密码、客户端身份,如果核对无误,则会生成Token(唯一的字符串),同时将Token存入缓存,并设置有效期。
(3)认证服务将Token返回给客户端。
(4)客户端收到Token后,将Token存储到Local Storage中。
(5)客户端后续访问系统其他资源(API)时,携带此Token并放入HTTPHeader的Authorization中,保证Token的安全性。
(6)资源服务器收到Token后,请求认证授权中心,验证Token的合法性。
(7)认证服务检查Token是否有效和是否过期,并将验证结果返回给资源服务器。
(8)如果Token无效,则拒绝访问受保护资源,有效则允许访问,完成业务处理。
(9)资源服务器返回业务处理结果。
这种思想是客户端先通过认证,获取访问令牌;然后再携带令牌访问服务器,其本质其实与Cookie很像,但是规避了Cookie的各种弊端。利用Token机制的协议和技术有很多,最常用的就是OAuth 2.0协议和JWT技术。
2.架构优点
(1)集中认证和授权,便于集中化地管理Token,系统架构更清晰,职责更单一。
(2)使用缓存服务器存储Token,访问效率更高,可以对Token做主动失效处理。
(3)一旦篡改Token,则Token立即无效,必须重新获取,保证了安全性。
(4)无限制水平扩展,架构弹性更好。
3.架构缺点
(1)认证中心除了要负责制作和发放Token,还要负责刷新、删除和验证Token。
(2)当服务请求量巨大时,认证服务器压力会较大。
5.8.2 SecretID和SecretKey模式
如果对接微信、支付宝、淘宝、阿里云等多租户的开放平台的API接口,就会看到SecretID和SecretKey模式设计。可以直接将SecretID和SecretKey模式理解为OAuth 2.0协议的密码模式,区别是这个用户名和密码不是直接给用户使用的,而是给接入方的系统使用的。
基于SecretID和SecretKey的安全控制流程如图5-38所示。
(1)首先会在云厂商的后台系统中新建自己的应用,平台会为应用生成SecretID和SecretKey,这就是客户端标识,也可以通俗地理解为服务器的用户名和密码。此时调用方的服务器相较于第三方平台,就变为了客户端的身份。
(2)使用SecretID和SecretKey请求第三方服务器。
(3)第三方服务器验证SecretID和SecretKey的有效性,并生成Token。
(4)第三方服务器将Token、有效期、刷新Token等信息返回给客户端。
(5)客户端携带Token去访问第三方服务接口,如发送短信、支付等。
其实SecretID和SecretKey模式本质上就属于Token模式,只是Token模式主要集中在服务端调用。
如果是处在内网环境中的服务器之间发生相互的调用,则也可以采用此种模式做安全控制,但是这会增加系统的复杂度、降低接口调用的效率,并且内网环境相对安全,因此不推荐采用此种模式,而是推荐采用直接调用的模式,或者OAuth 2.0协议的客户端模式。
如果将自己系统本身的某个接口开放给外部调用,非自己系统体系,也非公司内的其他服务调用,则一定要使用Token模式进行控制来增加安全性,并在网络设备上增加白名单,只允许特定IP的服务访问。
5.8.3 JWT模式
JWT(JSON Web Token)是一个开放的标准,定义了用于在各方之间交互的安全JSON对象。
1. JWT的组成结构
JWT本质上也是一个Token,它由三部分构成:Header(头部)、Payload(有效负荷)和Signature(签名),中间用符号“.”分隔。例如,下面的就是一个JWT串。
(1)Header(头部)。
Header通常由两部分组成。
- ① type:类型,一般为JWT。
- ② alg:加密算法,通常是HMAC SHA256或RSA。例如,{"typ":"JWT", "alg":"RSA"}。Header信息经过Base64UrlEncode加密,从而得到第1部分的加密串。
(2)Payload(有效负荷)。
Payload是用来携带有效信息的载体。
- ① Registered claims:注册声明,这是一组预定的声明,但并不强制要求。它提供了一套有用的、能共同使用的声明。主要有iss(JWT签发者)、exp(JWT过期时间)、sub(JWT面向的用户)、aud(接收JWT的一方)等。
- ② Public claims:公开声明,公开声明中可以添加任何信息,一般是用户信息或业务扩展信息等。
- ③ Private claims:私有声明,由JWT提供者和消费者共同定义的声明,既不属于注册声明,也不属于公开声明。
- ④ 不建议在Payload中添加任何敏感信息,因为Base64是对称加解密的,这意味着Payload中的内容都是可见的。
例如,{"AccountID":"19898921", "name":"Kevin" ,"timestamp":9878178281}。
Payload信息经过Base64UrlEncode加密,从而得到第2部分的加密串。
(3)Signature(签名)。
Signature用来放置签名信息,起到防篡改的作用。
- ① 将Header加密串和Payload加密串使用“.”连接起来,然后使用Header中alg的算法,再加上密钥进行加密,从而获得Signature加密串。
- ② 算法简写:RSA(Base64UrlEncode(header)+"."+Base64UrlEncode(payload), secrt)。最后将3段加密串使用“.”连接在一起,就得到了最终的JWT。
2. JWT安全控制流程
基于JWT的安全控制流程如图5-39所示。
(1)客户端请求认证服务,需要携带自身客户端标识、用户名和密码。
(2)认证服务验证无误,则将用户信息(用户ID、姓名等基本信息)封装在JWT的Payload部分,生成JWT,然后使用公钥进行加密,使用私钥进行签名。
(3)将JWT返回给客户端。
(4)客户端将JWT存储到Local Storage中。
(5)客户端携带JWT访问后端其他资源(接口)。
(6)资源服务器对JWT进行公钥验签和私钥解密,获取用户信息和有效时长,验证JWT是否有效,如果有效,则继续处理业务请求。
(7)将处理结果返回给客户端。
3. 架构优点
(1)在第2步并没有将JWT串存入Redis等缓存中,降低了系统设计的复杂度。
(2)在第6步资源服务器收到业务请求后,也没有携带JWT去认证中心验证其有效性。只要验签通过、解密正常,则认为JWT是一个合法的Token。解密后即可获取Token的过期时间、用户ID等信息,从而判断Token是否过期。因此,系统的压力被分散到各个资源服务器上,而不会与Token模式一样,压力集中在认证服务器上。
4. 架构缺点
(1)服务端的验签和解密会对服务器造成一定的压力,高并发场景下CPU承压增加。
(2)JWT一旦生成有效时间被固定,则不可更改,只能更换JWT。
(3)会话保持无法自动延长,只能由客户端自己控制,重新申请。
(4)JWT中可以存储业务敏感信息,存在一定风险。
5.8.4 微服务模式下的Token权限设计
在微服务架构下,可以充分利用网关来进行统一的Token验证,从而不需要每个资源服务器都实现Token验证,极大地简化了开发模式。
1.微服务架构下的Token权限设计
微服务架构下的Token权限设计如图5-40所示。
(1)客户端向网关发起Token申请,网关进行基础校验,校验客户端身份是否正确。
(2)网关将请求转发给认证授权中心(持有用户数据),申请新的Token。
(3)校验用户名和密码,并生成Token,存储到缓存中,设置有效期。
(4)认证授权中心将Token返回给网关。
(5)网关将Token返回给客户端,携带有效期和刷新码(用于刷新Token使用,与Token成对出现)。
(6)客户端将Token存储到Local Storage或Session Storage中,后续携带Token并放置在HTTP Header的Authorization中访问。
(7)当客户端需要访问资源服务器时,需要携带客户端标识和Token串,网关先进行客户端身份校验,如果通过,则直接从Redis中查询Token信息。
(8)如果网关可以查询到有效的Token数据,则通过校验并放行资源访问,否则拒绝访问。
2.架构优点
(1)认证授权中心统一发放、刷新和删除Token,集中管理。
(2)网关做统一的客户端身份校验、Token验证,避免了所有资源服务器开发。
(3)微服务网关除与认证中心搭配使用外,还可以结合JWT模式使用。
3.架构缺点
(1)由于所有的认证工作均由认证授权中心完成,因此认证授权中心的实现复杂度也相应提高。
(2)同样的原因,导致认证授权中心服务压力较大,需要做好高可用设计(避免单节点故障)和缓存设计(提高查询速度和并发能力)。
5.8.5 Token的延时与刷新
无论使用Token还是使用JWT,都会面临Token的延时和刷新问题。例如,用户成功登录了系统A,Token的有效时长为10分钟,用户正在进行支付操作,而此时Token刚好过期,就会导致用户被踢出,只能再重新登录和重新支付,显然是不合理的。
这就需要Token具有动态延时和刷新等能力,类似Session的自动延时功能。首先要区分延时和刷新这两个概念。
(1)Token延时:是指原Token不发生变化,只是重置Token的有效时长。例如,原Token还剩余1分钟过期,则延时之后Token有效时长恢复为10分钟。
(2)Token刷新:是指重新生成新的Token,Token串发生了变化,同时有效期恢复为10分钟。
1.自动延时设计
自动延时设计时模仿Session的延时效果,客户端每次携带Token访问服务 端时,如果服务端发现该Token有效,则会将Token的有效期恢复为10分钟。因 此,除非客户端10分钟内没有任何操作Token才会失效,超过10分钟后再操作 Token才会被踢出。 自动延时有一个致命的缺陷,就是一旦Token丢失,攻击方就可以使用此 Token,持续与服务端保持会话,Token相当于永久有效,所以笔者一般不建议 采用此种延时设计,而是采用刷新设计。
2. Token刷新设计
Token刷新一般有两种方式,即客户端主动刷新和服务端定时任务刷新。
(1)客户端主动刷新。
服务端生成Token后,会连同Token的有效时长和截止失效时间返回给客户端。Web或原生客户端在每次发起请求时都需要先判断Token是否即将过期,如果即将过期,则调用Token刷新接口重新获取Token,再使用新的Token去访问系统。
也可以在每次调用接口前,都重新获取一次Token,显然这种方式效率极低,因此不建议采用。
(2)服务端定时任务刷新。
可以在服务端定义定时任务,每隔几分钟去刷新一次Token,从而保证Token得到持续的延长和更换。
Token刷新设计流程如图5-41所示,包含以下4个步骤。
(1)客户端申请Token。
(2)认证服务生成并返回Token信息,Token一般由Token串和刷新Token串和有效时长三部分构成。
(3)客户端请求刷新Token,需要携带原Token串和refreshToken串。
(4)认证服务端需要比对原Token串是否有效,并且Token与refreshToken是否相互匹配,才会生成新的Token和refreshToken返回给客户端。
思考:为什么一定要客户端主动刷新,而不能服务端主动延时呢?
如果由服务端进行Token自动延时,则Token不会主动更换,除非客户端主动发起刷新操作。一旦Token泄露,则可以无限制调用后端接口,因为Token始终不变,并且持续有效。Token刷新设计的特点是必须定期更换,以保证更高的安全性。更换Token的方式有两种。
第一种是重新获取,那就必须提供客户端身份信息,同时提供用户信息(用户名和密码),除非所有信息均丢失,才会引发安全性问题,但是与平台无关,属于用户保存不当。
第二种是使用刷新码进行刷新,这种获取方式必须提供客户端身份信息、原Token和刷新码,三者全部丢失才会引发安全性问题。
5.9 章节练习
1.简单描述短信攻击的过程是什么?
在客户端(浏览器或App等)截获短信发送服务的接口地址和请求数据,然后通过程序模拟请求数据(可篡改目标用户的手机号),大批量调用短信发送服务,从而导致系统发送出大批量的短信,使被攻击者蒙受经济和名誉损失。
2.为什么Session、Token等用户登录的凭证信息都需要设置有效期?
如果用户登录系统后永久不过期,就会存在各种安全隐患。例如,用户登录系统后忘记了退出,其他人使用这台计算机时就可以直接进入系统,进行各种违法操作。
如果Session和Token信息被劫持,则攻击者可以随时假冒用户的身份访问系统,向服务端发送各种伪造请求,不会有任何限制,因为对于服务端来说接收到的都是合法请求。
如果设置了有效期,则即使以上两种情况发生,也能将损害程度降到最低。攻击者很快就会因为Session或Token失效,无法访问系统。
3.简单描述主动踢出和被动踢出是如何实现的,区别是什么?
主动踢出是利用消息推送技术,由后登录的用户设备向已经登录的设备推送踢出消息,客户端接收到消息后主动退出系统。
被动踢出是利用Session、Token等用户登录凭证信息的有效性进行控制,后登录的用户设备将申请服务端生成新的Session、Token信息,那么事前已经登录的用户再访问任意后端接口时,就会因为对应的Session、Token不存在而被踢出。
主动踢出用户体验更好,但是消息推送的延迟性和不稳定性会导致踢出失败的概率增加。而被动踢出虽然用户体验稍差,但是实现简单,不会出现踢出失败的情况,安全性更好。
实际应用时可以将两种方式相互结合,提升用户体验的同时增强安全性。
4.什么是上行短信,什么是下行短信?
上行短信是指用户主动给通信服务提供商发送的短信(如用户给10086发送的短信),下行短信是指通信服务提供商主动给用户发送的短信(如10086给用户发送的短信)。
5. RBAC权限模型是什么,有几种设计方式?
RBAC的全称是Role Based Access Control,即基于角色的访问控制,主要有用户角色权限模型、继承模型、用户组模型、权限组模型等。
6.怎样保证用户密码存储和传输的安全?
对用户密码进行加盐和哈希加密处理再存入数据库中,也可以经过多次加盐和多次哈希加密进一步增强安全性,防止密码被暴力解密。在网络传输中采用HTTPS进行传输,或者对用户的密码进行加密后再发送给后端服务。
5.10 案例设计
1.场景设计题:短视频用户中心案例设计
用户体系的管理在任何一个系统中都是重点和难点,现有一个亿级用户体量的短视频App系统,希望对用户进行集中的统一管理,请设计一个用户管理中心服务,需满足如下相关要求。
(1)负责对系统中上亿个用户的全生命周期的管理(从用户的创建到注销)。
(2)用户可以使用第三方账号(如微信、微博等)登录。
(3)企业有权冻结和解冻账号,用户可以主动注销账号,企业无权注销账号。
(4)用户之间可以互相关注、取消关注、发送消息。
(5)用户可以在PC、App、小程序等多端登录系统,观看小视频。
(6)为其他所有系统提供用户信息相关的服务。
如果您作为企业的系统架构师,会怎样进行系统设计,需要考虑哪些内容?
2.设计思路指引
(1)进行功能分析,得出用户中心应该具有哪些能力。
① 用户中心负责用户的全生命周期管理,首先需要考虑用户从创建到销毁,系统需要包含哪些与用户相关的系统功能,包括注册、登录、退出、忘记密码、修改密码、修改个人信息和注销共7个主要功能模块。
② 用户可以使用第三方账号登录,所以需要具有第三方账号绑定和解绑功能。
③ 企业有权冻结和解冻账号,所以需要具有用户冻结和解冻功能。
④ 用户之间可以相互关注、取消关注,所以需要具有好友功能,负责用户关系的存储和维护。
⑤ 用户可以在PC、App、小程序等多端登录系统,需要考虑多端多设备的登录和踢出设计。
⑥ 由于需要为其他系统提供服务,因此需要提供用户数据检索的开放接口服务。
(2)进行逐个功能的设计。
① 多端支持:支持PC、App、小程序等多端功能,在数据存储上需要记录诸如注册来源、登录来源等与应用标识相关的信息。
② 注册和登录:支持手机验证码、用户名密码、第三方账号注册和登录等多种方式,涉及与短信系统和第三方系统的对接设计。
③ 忘记和修改密码:需要发送短信或邮件进行验证,同时需要考虑增加图片验证码来增强安全性。
④ 踢出和退出:需要设计用户的退出方式(主动和被动退出),多端多设备登录的消息提醒和踢出设计。
⑤ 修改个人信息:用户要能主动修改自己的基本信息,以及更换手机号。
⑥ 第三方账号:要能够主动解除或换绑第三方账号,涉及与第三方系统的对接。
⑦ 注销:用户状态标记,不主动清除数据(可由用户决定)。
⑧ 好友管理:记录用户之间的关系图谱。
(3)进行非功能的设计:从性能、数据量的角度考虑。
① 用户数量达到上亿规模,用户表必须采用分库分表设计,并且按照用户ID为主键进行拆分。其他服务获取用户数据时强制要求通过ID获取,以加快检索效率。
② 其他业务数据库原则上只存储用户ID字段,而是通过用户中心的开放服务查询用户的完整信息。
③ 在一些特殊场景下为了加快查询速度,可以对必要的用户字段进行冗余存储。例如,短视频制作者要查看哪些用户购买了自己的产品,需要显示购买用户的昵称,如果每一笔订单都要去请求用户中心,根据ID查询一次用户昵称,速度就会十分缓慢。那么,就可以将用户的ID和昵称都存储到订单表中,从而一次性查询出来即可。
④ 冗余存储需要注意数据的一致性,如果用户更新了昵称,则用户的购买订单中冗余存储的昵称也要更新,但是并不要求那么高的实时性。
⑤ 用户服务中使用量巨大的主要是登录服务和用户信息查询服务(给其他子系统或微服务提供查询),因此对于这两个服务可以单独抽取为微服务,横向部署多个节点,以提供更好的服务性能。