简介
安全性不是越高越好,而是够用就好。
环境风险:
- 被偷窥的风险
- 被抓包的风险
- 被伪造的风险
两个概念:
- Authentication,用户认证,就是让用户登录,并且在接下来的一段时间内让用户访问网站时可以使用其账户,而不需要再次登录的机制。
- Authorization,用户授权,户授权指的是规定并允许用户使用自己的权限,例如发布帖子、管理站点等。
本文的主要脉络:
- 用户认证是什么,简单实现
- 基于token的实现
- 前两点是在同一公司站点内。那么扩展到不同公司的站点,比如访问开放服务,用户认证怎么做
具体工具
编码,防可见
Base64 is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation.
选用64个可见字符代表0~63, 以此将8bit转换为一个字符,进而将一个二进制数组(可以是json、字符串等任何文档)转换为字符串。关于Base64编码的理解
签名,防篡改
针对明文计算一个签名,传输时除明文外,还携带签名。在secret key没有暴露的前提下,接收方根据明文计算签名,如果签名一致,则表示明文内容没有被篡改。
目前笔者见到以下几种方式
- 将明文/明文base64编码 通过 HS256使用对称秘钥加密 加密,得到一个字符串。HS256是对称加密算法,与之对应的便是大名鼎鼎的RS256(即RSA)。
- 将明文 带上一个secret key 计算md5
密文,防可见 + 防篡改
RSA
有效期,防重放
用户认证
从服务端的角度说:服务端提供资源给客户端,但是某些资源是有条件的。所以服务端要能够识别请求者的身份,然后再判断所请求的资源是否可以给请求者。
从客户端的角度说:所谓用户认证(Authentication),就是让用户登录,并且在接下来的一段时间内让用户访问网站时可以使用其账户,而不需要再次登录的机制。
-
http 四种认证方式,HTTP认证与https简介
- basic 认证,
Authorization: Basic QWRlcGxveSdzIGJsb2c=
Basic之后是username=password
Base64加密后的值。本质就是每次http请求传输用户名和密码(没错,起初就是这么直接) - digest 认证,basic 认证 的加强版
- https client 认证,
- form based 认证,认证信息作为请求参数,类似于Http基本认证
- basic 认证,
- Cookie/Session 认证机制
- 基于 Token 的认证机制,基本与Cookie/Session 认证机制类似,只是“sessionid”不再由tomcat存储。
- oauth
本文主要讲下后两种认证方式,cookie、token机制使得用户一次登录后,其它时间的请求不用再携带用户名和密码。
token 认证
关于JWT的两篇演进文章
JSON Web Token - 在Web应用间安全地传递信息
八幅漫画理解使用JSON Web Token设计单点登录系统
要点如下:
-
JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。具体的说,接收方可以确保信息自发送方发出后,没有被篡改过。文中的例子很经典,
https://your.awesome-app.com/make-friend/?from_user=B&target_user=A
如果用户B触发url,则认为用户b愿意加A为好友。- 正常服务端逻辑。收到该请求,从请求中提取(比如cookie)用户B是否已登录的信息,如果确认是用户B,则进行相关操作。问题:该url可能在任何平台被触发,android/ios、网页、邮件中等,所以请求中不一定可以提取到用户B的登录信息。
- 所以服务器对用户是否登录不做限定
- 那么,用户b就可以任意添加好友了。
- 因此,采用签名等手段,防止用户b篡改url
-
使用token之后,我们不仅可以做用户认证(有这个token,并且token有效的话,就可以认为用户登陆过),其潜在的约定还包括token中包含uid之类的信息,可以识别用户的身份。我们知道,通过session id可以拿到服务器保存在session会话中的kv,那么从token中拿到uid信息后, 服务器可以根据uid作出个性化反应。认证不是目的,作出个性化反应才是。不得不说,token搞这么一圈,只是将session的实现原理“显式化”了。
同一个作者演进的两篇文章
token要能实现以下基本约束:
-
防伪造,哪怕算法泄漏
- token中包括uid、随机数等信息,服务端存储uid与缓存的映射。收到请求后,从token中解析出uid,然后查询服务端
<uid,token>
的映射,判断token是否匹配
- token中包括uid、随机数等信息,服务端存储uid与缓存的映射。收到请求后,从token中解析出uid,然后查询服务端
-
防冒充,拿着正常用户的token发送请求
- token 计算中加入有效期
-
防重放,抓包到客户端请求, 然后不停地repeat
对请求进行频控
基于token的多平台身份认证架构设计,该文章系统的论述了token系统理论问题
使用场景 | 来源 | 目的 | 有效期 | 过期后 |
---|---|---|---|---|
网站一般页面访问 | 服务端生成 | 省去每次输入用户名和密码的问题 | 7天到一个月 | 用户重新输入登陆密码以确认授权 |
支付场景 | 服务端生成 | 一次交易的多个环节(订单、扣款等)用户授权确认 | 一次交易一个token | 用户重新输入支付密码以确认授权 |
文件上传 | 客户端或服务端生成 | 服务端识别身份 | 看场景需求 | 服务端重新判断用户身份、占用资源等是否允许 |
推送APPKEY 和APPSercret | 使用apns的推送服务,需要向apple 申请应用和密钥 | 服务端识别身份 | 一年 | 向apple申请 |
可以看到,对于用户之于一个网站,不是一个token便可以到处使用。
- 对于不同的用途、不同有效期、不同的平台,要准备多个token
- 不只用在访问网站上,用户有用户名和密码,各种andriod/ios sdk、java sdk有appkey 和 secretykey,这就是sdk的“用户名”和“密码”,。
环境风险:
- 被偷窥的风险
- 被抓包的风险
- 被伪造的风险
有意思的地方,基于token的安全认证:先使用用户名密码得到一个token,以后的请求使用token。https:先根据证书(crt之类)沟通一个对称秘钥,以后的请求使用对称加密,异曲同工。
oauth
HTTP 支持几种认证方式
- Basic Authentication(基本认证),格式为 http://username:password@url,在实际发送请求之前,用户名和密码会被组合成一个字符串( username:password),然后整个字符串会被进行 Base64 编码,浏览器或客户端软件会在请求头中添加一个 Authorization 头部,类似于
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
,通常用于测试目的或在受信任的网络环境中,其中安全性不是主要关注点。 - OAuth 2.0,比如Bearer Token 是一种用于身份验证的访问令牌,它授权持有者(Bearer)访问资源的权限。Bearer Token 在 HTTP 请求头中以
Authorization: Bearer <token>
的形式发送,服务器会根据这个 Token 来验证请求者的身份并授权访问。PS: Bearer 是授权人的意思。
前文主要讲述同一公司的所有站点如何做用户认证,那么在不同公司的用户站点如何实现用户认证?OAuth工作原理随想——让你的系统提供的服务更加安全
很多人会使用网盘来存放一些文件,像照片、文档之类。当我们存取文件的时候,我们需要给网盘提供账户密码,这样网盘服 务就能验证我们的身份。账户密码作为认证方式,保证只有我们自己可以存取自己的文件。这个场景足够简单,但很快我们就遇到新需求:我们需要使用一个在线制作相册的应用。按正常的使用流程,我们需要把网盘的照片下载到本地,然后再把照片上传 到电子相册。这个过程是比较很繁琐的。我们能想到的优化方法是,让相册应用,直 接访问网盘来获取我们的照片,而这需要我们把用户名和密码授权给相册应用使用。这样的授权方式,优点显而易见,但缺点也是很明显的:我们把网盘的用户名密 码给了相册服务,相册服务就拥有了读写网盘的能力,从数据安全角度,这个是很可 怕的。
OAuth 协议是为了解决上述问题而设计的一种标准方案,相比把账户密码直接给三方应用,此协议采用了一种间接的方式来达到同样的 目的。
这个协议其实就做了两件事情:
- 在用户授权的情况下,三方应用获取 token 所表示的临时访问权限;
- 然后三方应用使用这个 token 去获取资源。
如果用网盘的例子来说明的话,那就是用户授权网盘服务给相册应用创建临时 token,然后相册应用使用这个 token 去网盘服务获取用户的照片。实际上 OAuth 2.0 各个变种的核心差别,在于第一件事情,就是用户授权资源服务器的方式。
资源服务器实际上扮演了鉴权和资源管理两种角色,这两者分开实现的话,协议流程会变成下图这样。
oauth 与网关
目前,SSO 的实现方案常见有以下几种:
- 基于 JWT:JWT(JSON Web Token)是一种用于在各方之间安全传递信息的开放标准,令牌中包含用户的身份信息和权限。然而,JWT 用于 SSO 时缺乏标准化方案,导致集成复杂,且令牌一旦签发无法撤销,可能影响安全性。
- 基于 CAS:CAS(Central Authentication Service)是一种基于中间件的开源单点登录解决方案,通常用于大学和大型企业。用户在一处登录后即可无缝访问所有与 CAS 集成的应用。但其实现较为复杂,对系统集成要求较高。
- 基于 SAML:SAML(Security Assertion Markup Language)是一种协议,用于在应用程序与 SSO 服务之间交换身份验证信息。它使用 XML 来交换用户标识数据,提供高安全性和灵活性,但配置和实施较为复杂,增加了开发和维护成本。
- 基于 OIDC:OIDC(OpenID Connect)是基于 OAuth 2.0 的身份验证层,允许用户通过多种客户端(如 Web 应用、移动应用等)进行身份验证。OIDC 具有标准化、简单易用、灵活性和安全性等优点,成为许多企业在实现单点登录时的首选。OIDC 还有广泛第三方服务提供商的支持,如支付宝、钉钉、微信、GitHub 等。
网关作为后端服务所有请求的入口,可以集成 OIDC 实现统一认证服务,所有后端服务不需要各自实现用户认证逻辑,而是统一通过网关进行用户身份的验证。这样简化了系统架构,减少了重复工作,并提高了安全性。用户在网关配置 OIDC 认证鉴权,可以实现对资源的细粒度访问控制。并且可以方便地对接自建的身份认证服务,或者社交媒体账号等其他第三方账户登录,增强了业务的便利性。
- 有一个用户管理(登陆注销)系统,比如叫paasport,用户登录后获取一个key,之后用户请求携带key 访问其它业务服务,每个业务服务 拿到key 之后请求paasport 拿到用户信息(这个逻辑一般在filter中),再进行业务处理。此时网关对用户信息这块无感并透明。
- 根据key 获取用户信息这个动作 过于通用,因此可以转移到网关上。 结合oauth 或openid connect 协议,很多网关也会支持对应插件。将用户请求的key 转为用户信息(比如uid)附着在请求上,后端的业务系统无需关心用户信息。
其它
“一切历史都是现代史”,搞清楚来龙,有助于更好的理解原理。