通用安全的token化解决方案

一、协议过程

a. 我们先来看token化的协议过程 

通用安全的token化解决方案

图 一.a

在用户输入正确的用户名和密码后,"图 一.a" 中 Step "2." 将tokens放入到cookie中,  拿点融举例子,我们会将cookie放到 ".dianrong.com”这个域名下。看起来非常简单,认证、单点登陆全都有了。

 b. 我们再来看一看CAS的SSO协议过程

通用安全的token化解决方案

图 一.b

图 一.b 描述了开源应用CAS定义的单点登陆协议

有重定向、有指定service, 临时ticket传递、有后台有状态ticket的验证,整个流程步骤比较多。倘若我们的应用是单页的前后端分离应用,前端和后端仅通过ajax进行访问,在重定向这一步会卡住。

点融的应用几乎都是前后端分离,我们针对这种情况做了一些定制(本文重点不是这个, 有兴趣可以找作者)。

 

通过这个协议过程的对比,我们发现,token无疑提供了更高的便捷性。

二. Token化的优点和缺点

优点:

• 无状态、性能 —— token机制在服务器端不需要存储session信息,因为token自身可包含登陆用户的信息,例如 手机号、用户id,在客户端cookie存储这个信息从性能上来讲, 节省一次网络,仅做一次token的验签,将io消耗转换为cpu消耗.

• 解耦 —— token在内网生成,可由任意一个集成了SDK的服务器端 设置到客户端,它的生成 和 验证方案可随意切换,中心服务器用于维护状态

• 适用于现代Clients —— 比如微信小程序、比如原生平台

• 便捷 —— 集成方便、测试方便、客户端透明

• 标准 —— 比如RFC7519,使用JWT格式,可以跨平台

ps: token化之后,token理论上可以交给前端,由前端自己决定保存方式、传递方式,也因此可以实现跨域变得更加方便方式。 但由此而引出的安全问题后端无法掌控,因而我不认为跨域访问是一个优势, 跨域的授权, 应该由oauth2.0协议来完成。

缺点:

• Security —— 便捷 和 安全是一对好伙伴,在获得便捷的同时应当考虑安全性是否下降

• Revoke token —— token无状态,属于Bearer Token 因此无法对已经签发的token进行撤销, 只能等待其失效. 

• Renew token —— token无状态,所以不会像session随着每一次的访问而修改session失效时间.

三、平衡缺点,获得优点

A. Security

为了尽可能的限制安全问题发生的范围,我们生成的所有token都会放入cookie并且cookie.setMaxAge(-1), 常见的security问题以及其解决方案:

1. Man-in-the-Middle. 使用https加密,避免中途有人监听窃取cookie, 以java代码为例, cookie new出来之后需要 setSecure=true, 只在https的情况下设置cookie.

2. Cross-Site Scripting (XSS),  cookie new出来之后需要 setHttpOnly=true, 这样js代码就无法操作cookie, 自然XSS无处遁寻。针对服务器端 和 非WEB客户端,则需要分别保证自己依赖的library不包含可执行代码,客户端保证服务器返回的任何内容都有执行类似escapeHtml的操作.

3. Cross-Site Request Forgery (CSRF), 在访问某些比较敏感接口时(比如转账),使用Double-Submit Cookie方案解决。 这个安全问题有一点需要注意:不要滥用CORS(cross origin resource share), 这样会导致 CSRF方式的漏洞, 完全暴露给恶意攻击者。

B. Renew & Revoke token

想要克服无状态的这两个缺点,首先看 两个概念 : Access & refresh token签名tokens

• Access token拥有比较短的生存时间, 可以被认作为一个无状态的可信任的字符串。

• Refresh token拥有比较长的生存时间,是用来换取access token的。refresh token应该可以被撤销(Database + cache). 

        基于这两个从oauth2借来的概念,我们的方案如图:

通用安全的token化解决方案

图 三.a server-side use case

通用安全的token化解决方案

图 三.b client-side 流程图

如图三.b,  我们将refresh token有状态化,通过对refresh token的控制,从而达成对token renew&revoke的目的。

通过Access Token & Refresh token pair 的有效期的配置,我们即拥有了token无状态的优势(由access token提供),也拥有了控制token状态的能力。

以下举一些常见的token可配置的例子:

• 敏感应用(如 银行app)

            Access token TTL(Time to live) : 1 minute

            Refresh token TTL : 30 minutes

• 普通应用

            Access token TTL: 5 minutes

            Refresh token TTL : 2 hours

• 特殊身份不敏感应用(如今日头条、抖音)

            Access token TTL = 1 hour

            Refresh token TTL = 2 years

Balance是程序员世界很有趣的话题。

 

四、签名 & 验签 算法

RSA or HMAC or others?

主要从两个维度考虑问题:

1. 安全

2. 性能

RSA 算法的安全基于大数因式分解,而大数因式分解无特效公式,因此RSA只要密钥/公钥对足够大,就足够安全。我在我本机做了一些性能测试, 将签名内容SHA256之后用RSA算法签名验签时间如下:

    * 4096位RSA私钥公钥对 签名 --> 每个49.36ms, 验签 --> 每个 0.6667ms

    * 2048位RSA私钥公钥对 签名 --> 每个6.43ms, 验签 --> 每个 0.1844ms

    * 1024位RSA私钥公钥对 签名 --> 每个1.088ms, 验签 --> 每个 0.0548ms

RSA 私钥和公钥不一样,在token做authentication的case中,签名使用私钥,验签使用公钥。

在内网,可以仅将公钥交给非签发签名的系统来验签(防止其他系统泄露私钥), 而私钥仅由签发签名的系统保管。

HMAC 只有密钥,签名验签很快,  客户端知道密钥,易泄露。

不论用哪种算法,都不需要将公钥或私钥交给前端。

 

五、总结

• Token放进cookie, Cookie 应该 setSecure = true , httpOnly,   .domain.com, setMaxAge(-1)

• Access Token + Refresh Token的方式 是一个非常好的scaling 策略

• 每一次使用refresh token(如 获取新access token、refreshtoken) 都需要访问服务器询问其状态

六.其他风险

•    签名密钥泄露

•    密钥被破解

签名密钥泄露之后,理论上得到密钥的人可制造任意被服务器相信的内容。需要系统拥有随时更换密钥的能力、周期性的更换密钥。

七、Reference Links:

• 流程图地址: 

https://www.processon.com/view/link/5ae9249de4b09b1bf6369cba

• 滴滴passport经验:

http://www.hello-code.com/blog/architecture/201607/6099.html

• 讲真别再用JWT了!

https://www.jianshu.com/p/af8360b83a9f

• OWASP:

https://www.owasp.org/index.php/JSON_Web_Token_(JWT)_Cheat_Sheet_for_Java#Token_weak_secret

• Building Secure User interfaces With JWTs(JSON Web Tokens) : 

https://www.slideshare.net/stormpath/building-secure-user-interfaces-with-jwts

本文由来源 点融黑帮,由 congtou 整理编辑,其版权均为 点融黑帮 所有,文章内容系作者个人观点,不代表 华盟网 对观点赞同或支持。如需转载,请注明文章来源。

2

发表评论

// 360自动收录 // 360自动收录