鉴权方案实现小结

鉴权方案实现小结

首先贴上业内的四种解决方案,这是看下来写的比较不错的文章:前后端常见的几种鉴权方式

目前我们常用的鉴权有四种:

  1. HTTP Basic Authentication
  2. session-cookie
  3. Token 验证
  4. OAuth(开放授权)

第一种基于http自带的鉴权是比较古老的方式,用的比较少,安全性较低

第二种是大家都耳熟能详的通过session - cookie来维持用户登录状态,一般课本教的都是这种,弊端非常多,如下:

  1. 只适用于web系统(其他终端没有cookie一说)
  2. session的内存占用:每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大
  3. 分布式session的问题:分布式环境下,如何保证session在多台机器间共享(解决思路:1.共享存储(redis);2.只使用cookie(类似于token验证);3.Nginx负载均衡策略按ip hash(保证同一用户的请求打到同一台机器))
  4. CSRF风险:由于依赖cookie进行用户识别,cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击

第三种使用Token,目前的主流思路,适用于app鉴权,微信开发平台access token也是差不多这种思路。具体的实现有JWT(JSON WEB TOKEN) ,JWT的主要优势在于使用无状态、可扩展的方式处理应用中的用户会话。服务端可以通过内嵌的声明信息,很容易地获取用户的会话信息,而不需要去访问用户或会话的数据库。在一个分布式的面向服务的框架中,这一点非常有用。

第四种的使用场景主要在需要第三方授权时使用,如豆瓣可以通过qq授权登录

刚看完token和OAuth的时候感觉两者的实现有些类似,贴一段比较(来源:OAuth 2和JWT - 如何设计安全的API

JWT和OAuth2比较?

​ 要比较JWT和OAuth2?首先要明白一点就是,这两个根本没有可比性,是两个完全不同的东西。

  • JWT是一种认证协议
    JWT提供了一种用于发布接入令牌(Access Token),并对发布的签名接入令牌进行验证的方法。 令牌(Token)本身包含了一系列声明,应用程序可以根据这些声明限制用户对资源的访问。
  • OAuth2是一种授权框架
    另一方面,OAuth2是一种授权框架,提供了一套详细的授权机制(指导)。用户或应用可以通过公开的或私有的设置,授权第三方应用访问特定资源。

既然JWT和OAuth2没有可比性,为什么还要把这两个放在一起说呢?实际中确实会有很多人拿JWT和OAuth2作比较。标题里把这两个放在一起,确实有误导的意思。很多情况下,在讨论OAuth2的实现时,会把JSON Web Token作为一种认证机制使用。这也是为什么他们会经常一起出现。

这个感觉很像Java中的依赖反转(IOC)和依赖注入(DI)的关系,即依赖反转是思想,注入是其常见的实现方式。

更进一步地,JWT是OAuth2协议中授权码模式的一种具体实现(深入聊聊微服务架构的身份认证问题)

想起当时网易面试就被问到了cookie - session 的分布式session问题,当时我答通过数据库😂。。。后来池哥和我说仅仅使用cookie就可以了,把所有信息都存储在cookie中, 其实就是token的实现方式

项目中鉴权方案的升级

在对外的开放平台项目中,也用到了token的鉴权方式,实现方式与腾讯云 - 接口鉴权非常相似(看了看各公司提供的鉴权方案,大同小异,均是token的实现方式),我接手的版本没有包括一个时间戳,然后有一个业务场景是先对用户的套餐进行扣费,再返回收费资源的下载链接,这时候有一个风险是如果此时这个收费资源的链接被拦截了,或者用户恶意放到网上,那后果是所有人都能通过这个链接直接访问收费资源(鉴权信息都包含在返回的下载链接中的token里了)

类似的问题让我第一个想到了百度网盘的收费资源,于是去查了下实现方式,网上没有具体的说明,但通过几次测试(先在一个浏览器中通过验证,随即打开新的浏览器尝试先前验证后的url,发现需重新验证)猜测是通过localStorage实现(即把验证信息放在localStorage中,每次发起请求带上这个信息,又下载资源无需登录,排除cookie)

由于open平台不是B/S架构,故不能通过cookie或者localStorage实现,又想了想几个解决方案:

  1. 传输用https协议,避免CSRF的攻击(已采用)
  2. 下载url的token中绑定用户ip
  3. 设置下载的上限次数(已采用)
  4. 设置链接的超时时间(可以在token中加入时间戳之后每次在内存中验证,也可以把这个key放入redis并设置timeout,每次setnx即可判断是否超时)
  5. 更改接口,类似于第三方验证的机制,第一次访问扣费后不再直接拿到资源下载的链接,而是返回一个accessToken代替,客户端真正下载再次访问时需加入该字段,服务器重新进行鉴权判断

最后在2、4、5三种思路中选择了最轻量的设置较短的超时时间完成鉴权方案的升级,同时为了平滑升级,保留了原有接口,新接口通过拦截器统一加v2完成分组路由,最少限度地更改原有代码。

最后贴上当时V2EX发的讨论贴:https://www.v2ex.com/t/566566#reply19,自己想不到优雅的解决办法的时候,可以发个贴试试🏷

附业内的一些鉴权接口文档:

腾讯云 - 接口鉴权

阿里云 - 视频安全 -URL鉴权

阿里云 - HTTPDNS -鉴权解析接口

Author: Apiao
Link: https://Apiao-1.github.io/2019/06/11/2019-06-11/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.