写点什么

App 长登录思考与实现

作者:石君
  • 2022-12-01
    北京
  • 本文字数:2879 字

    阅读完需:约 9 分钟

App长登录思考与实现

从最基本的用户体验来讲,不论 app 打开高频与否,保持 app 的登录状态,或者叫长登录,都是一种看似自然的选择。但综合监管要求、心理学感受、用户体验等因素,决策 App 长登录状态的十字路口,产生了分岔。

本文将综合讨论围绕金融类 App 长登录状态的各种要求,然后给出一些常见的解决方案。如此这样稀松平常、一闪而过的功能里,也有这么多知识点。


一、监管要求

《JR/T 0092-2019 移动金融客户端应用软件安全管理规范》

5.1.1 认证方式增强要求:b)在用户身份认证后,客户端应用软件进入终端系统后台时,如果超过设定时限后被唤醒切换到前台,应采取措施对用户身份重新认证。


《JR/T 0068-2020 网上银行系统信息安全通用规范》

6.2.1.1 客户端程序基本要求:o)客户端程序登录后一段时间内无任何操作,应自动登出,重新登录才能继续使用。


看来监管对于金融类客户端的要求还是挺高的。金融类应用属于刚需,再进一步细分,支付类属于高频、银行类属于低频,证券基金类应用的使用频次则因人而异。


但不管怎样,金融类应用一般都是以 app 的形式出现。这里面的原因,既有轻应用统一运行平台做限制的技术原因(例如微信小程序代码包上限 16M,支付宝是 8M),也有出于安全考虑做出限制的政策原因(例如 2017 年 1 月证监会下发指导意见禁止通过小程序开展基金交易)。所以,如何在满足监管要求的前提下,安全地实现 App 长登录、提升用户体验,是个技术活。


二、技术方案

要实现 App 长登录,必然要保存一些凭据,凭据或者放到客户端,或者放到服务器端。常见的长登录实现方式有如下几种:

1、session 方式

这种方式最大的优点是服务端不用增加任何代码,但 APP 与网站不同,通常情况下,我们会希望 APP 的登陆状态能维持数天,甚至数月之久,大部分的服务端程序,都会在进程重启时或客户端多久不活动时,将 session 全部清空,致使状态丢失,满足不了长登录需求。

2、用户名+口令方式

利用用户名和口令保持登录是指用户在第一次登录成功时,把用户名和口令保存在本地(比如多次 hash 后保存到 localStorage 中),下次用户打开 App 时登录利用保存的用户名和口令在后台自动完成,每次调用接口的时候都把它当成一个字段、参数传给后台。服务端每次都需要读取数据库判断合法性,增大服务器开销。此外,这种方式的安全风险较高,1 是需要考虑用户名和口令的安全问题,本地数据容易被攻击、破解;2 是无法防范拷贝攻击,如果 token 被人拷走,并植入到自己的手机里面,就可以以 token 登录态身份打开对应的 App。如果 App 和后端通信不是通过 http 协议进行的,也适合这种方式。

3、token 方式

为避免一次一验无谓开销,出现了只在客户端保存的 token 方式。token 是什么?token 其实就是访问资源对凭证。一般是用户通过用户名和口令登录成功之后,服务器将登录凭证做数字签名,加密之后得到的字符串就是 token。

App 初始登录时,提交账号和口令给服务端,服务端根据定义的的策略(比如 uid+timestamp+对应 uid 的唯一密钥)生成一个 token 字符串。服务端把生成的 token 字符串传给客户端,客户端保存 token 字符串,并在接下来的请求中带上这个字符串。后端保存一份同样的 token,并设置有效期,在 token 有效期范围内,用户都不需要重新登录。有效期之外则需要重新登录。具体实现方式举例:

(1)用 session 值作为 token

服务端接收到用户名、口令后做判断,如果正确了就生成 sessionID 并作为 Token 返回给客户端,客户端以后只需带上请求数据即可。这种方式优缺点都很明显,优点在于 sessionid 本来就存在于会话之中,不需要额外计算,就能使用;缺点在于这种方式仅利用了 sessionid 这一个字段做会话保持,有效期要设置多久呢?sessionid 总要在客户端保存,保存方式一般有 SharedPreferences、local storage、sqlite,有效期长了难以应对拷贝攻击,短了无意义。这是问题之一。其二,sessionid 在不安全的互联网传输时,一般要放到 request header 中(如下图所示,放 url 中不安全、body 数据太杂不方面解析),不论是因为拷贝攻击还是被中间人劫持了(http 传输中劫持、https 本地劫持),token 丢了身份就彻底丢了,就跟丢出入证一样,捡到的人就是能够冒充你的身份进入大楼,不具有“后向”安全能力。


(2)结合设备号/设备指纹生成 token

为了解决拷贝攻击安全问题,出现了一种使用设备号/设备指纹作为 token 的方式。这种方式在第一次登录的时候,除了账号口令之外,还会带上移动终端的设备号/设备指纹信息给后端,后会把设备指纹信息存储起来作为另一个。前端在把 token 传输上来的时候,也会把设备指纹传过来,两个字段都要做对比。这样 token 就与当前在用的设备产生了关联关系,换了设备就需要重新登录了,其他时候其实都不需要重新手动登录,也就是说允许用户主动更换设备,token 自动失效;但作为唯一的身份标识字段,token 丢失的问题仍未解决。

这种方式需要用到设备信息、需要用户授权,用户不给可能效果就会打折扣。根据《常见类型移动互联网应用程序必要个人信息范围规定》,不给这种非必要权限就不让用户使用了,可能还真的会产生合规风险。国家互联网信息办公室、工业和信息化部、公安部、国家市场监督管理总局联合制定的《常见类型移动互联网应用程序必要个人信息范围规定》,明确移动互联网应用程序(App)运营者不得因用户不同意收集非必要个人信息,而拒绝用户使用 App 基本功能服务。其中手机银行类 app 的必要个人信息仅包含:

(二十四)手机银行类,基本功能服务为“通过手机等移动智能终端设备进行银行账户管理、信息查询、转账汇款等服务”,必要个人信息包括:1.注册用户移动电话号码;2.用户姓名、证件类型和号码、证件有效期限、证件影印件、银行卡号码、银行预留移动电话号码;3.转账时需提供收款人姓名、银行卡号码、开户银行信息。


有过开发经验的同学可以马上发觉,这不就是 JWT 嘛,没错,因为以下几个有点,JWT 形式的 token 成为实现这种方式最常见的技术手段:

  • 数据量小,传输速度快;

  • 以 JSON 键值对形式保存在客户端的,跨语言,原则上任何 web 形式(包括移动应用)都支持;

  • 不需要在服务端保存会话信息,不依赖于 cookie 和 session,特别适用于分布式微服务;

  • 适用单点登录:token 可以被保存在客户端,不依赖于 cookie,特别适合单点登录


JWT 交互过程如下:

  1. 在登录验证通过后,给用户生成一个对应的 token,然后将这个 token 作为 key 的一部分,用户信息作为 value 存入 Redis,并设置过期时间,这个过期时间就是登录失效的时间

  2. 将上一步中生成的 token 作为 JWT 的 payload(注意,token 是 JWT 的一部分,JWT 包括 header、payload、signature 三部分)生成 JWT 字符串返回给前端

  3. 前端之后每次请求都在请求头中的 Authorization 字段中携带 JWT 字符串

  4. 后端定义一个拦截器,每次收到前端请求时,都先从请求头中的 Authorization 字段中取出 JWT 字符串并进行验证,验证通过后解析出 payload 中的 token,然后再用这个 token 得到 key,从 Redis 中获取用户信息,如果能获取到就说明用户已经登录,否则则需要重新登登录。


4、双 token 方式

虽说一直在改进,但 token、设备指纹毕竟是从终端取过来的,中间人同时做替换,也有可能造成身份替换。业界逐渐出现双 token 的模式,以及对 token、设备指纹按需存储的技术。(tobecontinued...)

发布于: 刚刚阅读数: 5
用户头像

石君

关注

与其更好,不如不同 2020-03-26 加入

分享孤独,成为故事,分享思考,成为思想。 做信息安全领域的探险家。

评论

发布
暂无评论
App长登录思考与实现_信息安全_石君_InfoQ写作社区