认识单点登录中的概念cookie、session、token、jwt以及认证协议outh2、saml

1,284 阅读22分钟

1、前言

1.1、单点登录

(1)单点登录的优势

①集中管理:借助 SSO 可以确保系统更加安全,我们只需要一台集中式服务器来管理用户身份,而不需要将用户凭证扩展到各个服务,因此能够减少被攻击的维度;

②系统间无缝连接:SSO 将不同的服务组合在一起,以便用户可以在服务之间进行无缝导航,从而提高用户体验。

③更好地构建用户画像。

(2)常用的单点登录方式

单点登录模式优点缺点
共享Cookie模式简单方便,用户体验好根域名需限制一致;Cookie可能不安全
跨域设置Cookie用户体验好,不受站点限制比较麻烦;Cookie可能不安全
客户端模式用户体验好,不受站点限制成本极高,依赖于用户本地安装客户端应用
OAuth2.0模式灵活安全,不受站点限制成本稍高,需独立的认证中心

(3)常用的设计

采用 OAuth2 协议是一个不错的选择,因为实现过程非常简单。虽然 OAuth2 一开始是用来允许用户授权第三方应用访问其资源的一种协议,也就是说其目标不是专门用来实现 SSO,但是我们可以利用它的功能特性来变相地实现单点登录,这就需要用到 OAuth2 四种授权模式中的授权码模式。同时,在使用 OAuth2 协议实现SSO时,我们也会使用 JWT 来生成和管理 Token。

多个站点共用一台认证授权服务器(用户数据库和认证授权模块共用)。用户经由其中任何一个站点登录后,可以免登录访问其他所有站点。而且,各站点间可以通过该登录状态直接交互。

1.2、各种名词解释

(1)Authentication 认证

验证当前用户的身份,常用的几种认证方式:用户名密码登录、邮箱发送登录链接、手机号接收验证码

(2)Authorization 授权

用户授予第三方应用反问用户某些资源的权限,例如:安装手机应用的时候,APP 会询问是否允许授予权限(访问相册、地理位置等权限)、访问微信小程序时,当登录时,小程序会询问是否允许授予权限。实现授权的方式有:cookie、session、token、OAuth。

(3)Credentials 凭证

实现认证和授权的前提是需要一种媒介(证书) 来标记访问者的身份

(4)Cookie

由于HTTP 是无状态的协议(对于事务处理没有记忆能力,每次客户端和服务端会话完成时,服务端不会保存任何会话信息):每个请求都是完全独立的,服务端无法确认当前访问者的身份信息,无法分辨上一次的请求发送者和这一次的发送者是不是同一个人。所以服务器与浏览器为了进行会话跟踪(知道是谁在访问我),就必须主动的去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一浏览器。而这个状态需要通过 cookie 或者 session 去实现。

cookie 存储在客户端:  cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。

cookie 是不可跨域的: 每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)

cookie的一些重要属性:

属性说明
name=value键值对,设置 Cookie 的名称及相对应的值,都必须是字符串类型 - 如果值为 Unicode 字符,需要为字符编码。 - 如果值为二进制数据,则需要使用 BASE64 编码。
domain指定 cookie 所属域名,默认是当前域名
path指定 cookie 在哪个路径(路由)下生效,默认是 '/'。 如果设置为 /abc,则只有 /abc 下的路由可以访问到该 cookie,如:/abc/read。
maxAgecookie 失效的时间,单位秒。如果为整数,则该 cookie 在 maxAge 秒后失效。如果为负数,该 cookie 为临时 cookie ,关闭浏览器即失效,浏览器也不会以任何形式保存该 cookie 。如果为 0,表示删除该 cookie 。默认为 -1。比 expires 好用。
expires过期时间,在设置的某个时间点后该 cookie 就会失效。 一般浏览器的 cookie 都是默认储存的,当关闭浏览器结束这个会话的时候,这个 cookie 也就会被删除
secure该 cookie 是否仅被使用安全协议传输。安全协议有 HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。 当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。
httpOnly如果给某个 cookie 设置了 httpOnly 属性,则无法通过 JS 脚本 读取到该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,所以只是在一定程度上可以防止 XSS 攻击,不是绝对的安全

(5)Session

session 是另一种记录服务器和客户端会话状态的机制,session 是基于cookie 实现的,session存储在服务器端,sessionId会被存储到客户端的cookie中

图片.png

session 认证流程:

· 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session

· 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器

· 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名

· 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。

Cookie和Session的区别

安全性: Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。
存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。
有效期不同: Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
存储大小不同: 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。

(6)Token 令牌

token是访问资源接口(API)时所需要的资源凭证,简单的token由以下组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)。token的特点是:服务端无状态化、可扩展性好,支持移动端设备、安全、支持跨程序调用。token的验证流程:

图片1.png

· 每一次请求都需要携带 token,需要把 token 放到 HTTP 的 Header 里

· 基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用解析 token 的计算时间换取 session 的存储空间,从而减轻服务器的压力,减少频繁的查询数据库

· token 完全由应用管理,所以它可以避开同源策略

(7)Refresh Token

refresh token 是专用于刷新 access token 的 token。如果没有 refresh token,也可以刷新 access token,但每次刷新都要用户输入登录用户名与密码,会很麻烦。有了 refresh token,可以减少这个麻烦,客户端直接用 refresh token 去更新 access token,无需用户进行额外的操作。

Refresh Token 及过期时间是存储在服务器的数据库中,只有在申请新的 Acesss Token 时才会验证,不会对业务接口响应时间造成影响,也不需要向 Session 一样一直保持在内存中以应对大量的请求.

使用refresh token的目的,为了职责分离,refresh token负责身份认证,而access token负责请求资源。

图片2.png

(8)Token和Session的区别

· Session 是一种记录服务器和客户端会话状态的机制,使服务端有状态化,可以记录会话信息。而 Token 是令牌,访问资源接口(API)时所需要的资源凭证。Token 使服务端无状态化,不会存储会话信息。

· Session 和 Token 并不矛盾,作为身份认证 Token 安全性比 Session 好,因为每一个请求都有签名还能防止监听以及重放攻击,而 Session 就必须依赖链路层来保障通讯安全了。如果你需要实现有状态的会话,仍然可以增加 Session 来在服务器端保存一些状态。

· 所谓 Session 认证只是简单的把 User 信息存储到 Session 里,因为 SessionID 的不可预测性,暂且认为是安全的。而 Token ,如果指的是 OAuth Token 或类似的机制的话,提供的是认证和授权 ,认证是针对用户,授权是针对 App 。其目的是让某 App 有权利访问某用户的信息。这里的 Token 是唯一的。不可以转移到其它 App上,也不可以转到其它用户上。Session 只提供一种简单的认证,即只要有此 SessionID ,即认为有此 User 的全部权利。是需要严格保密的,这个数据应该只保存在站方,不应该共享给其它网站或者第三方 App。所以简单来说:如果你的用户数据可能需要和第三方共享,或者允许第三方调用 API 接口,用Token 。如果永远只是自己的网站,自己的 App,用什么就无所谓了。

(9)JWT

JSON Web Token(简称 JWT)是目前最流行的跨域认证解决方案,是一种认证授权机制。JWT 是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准(RFC 7519)。JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。可以使用 HMAC 算法或者是 RSA 的公/私秘钥对 JWT 进行签名。因为数字签名的存在,这些传递的信息是可信的。

JWT的使用:客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。

方式一:当用户希望访问一个受保护的路由或者资源的时候,可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求头信息的 Authorization 字段里,使用 Bearer 模式添加 JWT。

GET /calendar/v1/events
Host: api.example.com
Authorization:  Bearer <token>

方式二:放在POST请求结构体中

方式三:直接通过URL传输

(10)Token和JWT的区别

JWT包含的内容更多。Token:服务端验证客户端发送过来的 Token 时,还需要查询数据库获取用户信息,然后验证 Token 是否有效。JWT: 将 Token 和 Payload 加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT 自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。

(11)常见的加密算法

图片.png

1.3、问题

(1)Cookie

因为存储在客户端,容易被客户端篡改,使用前需要验证合法性; 不要存储敏感数据,比如用户密码,账户余额;
使用 httpOnly 在一定程度上提高安全性;
尽量减少 cookie 的体积,能存储的数据量不能超过 4kb;
设置正确的 domain 和 path,减少数据传输;
çookie 无法跨域;
一个浏览器针对一个网站最多、存 20 个Cookie,浏览器一般只允许存放 300 个Cookie;
移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

(2)Session

将 session 存储在服务器里面,当用户同时在线量比较多时,这些 session 会占据较多的内存,需要在服务端定期的去清理过期的 session

当网站采用集群部署的时候,会遇到多台 web 服务器之间如何做 session 共享的问题。因为 session 是由单个服务器创建的,但是处理用户请求的服务器不一定是那个创建 session 的服务器,那么该服务器就无法拿到之前已经放入到 session 中的登录凭证之类的信息了。

当多个应用要共享 session 时,除了以上问题,还会遇到跨域问题,因为不同的应用可能部署的主机不一样,需要在各个应用做好 cookie 跨域的处理。

sessionId 是存储在 cookie 中的,假如浏览器禁止 cookie 或不支持 cookie 怎么办? 一般会把 sessionId 跟在 url 参数后面即重写 url,所以 session 不一定非得需要靠 cookie 实现

移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

(3)token

token和session的主要区别是,token使服务端无状态化了。

如果你认为用数据库来存储 token 会导致查询时间太长,可以选择放在内存当中。比如 redis 很适合你对 token 查询的需求。

token 完全由应用管理,所以它可以避开同源策略

token 可以避免 CSRF 攻击(因为不需要 cookie 了)

移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token

(4)JWT

JWT 不依赖 Cookie ,所以可以使用任何域名提供API 服务而不需要担心跨域资源共享问题(CORS)

JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次

JWT 不加密的情况下,不能将秘密数据写入 JWT

JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数

JWT 最大的优势是服务器不再需要存储 Session,使得服务器认证鉴权业务可以方便扩展。但这也是 JWT 最大的缺点:由于服务器不需要存储 Session 状态,因此使用过程中无法废弃某个 Token 或者更改 Token 的权限。也就是说一旦 JWT 签发了,到期之前就会始终有效,除非服务器部署额外的逻辑

JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

JWT 适合一次性的命令认证,颁发一个有效期极短的 JWT,即使暴露了危险也很小,由于每次操作都会生成新的 JWT,因此也没必要保存 JWT,真正实现无状态

为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输

总之,JWT最大的作用是应用于分布式系统和减轻服务器存储状态信息的开销,但还是有其缺点:

1、服务器无法控制token失效;
2、token到期失效后的自动刷新

(5)加密算法

绝不要以明文存储密码

永远使用 哈希算法 来处理密码,绝不要使用 Base64 或其他编码方式来存储密码,这和以明文存储密码是一样的,使用哈希,而不要使用编码。编码以及加密,都是双向的过程,而密码是保密的,应该只被它的所有者知道, 这个过程必须是单向的。哈希正是用于做这个的,从来没有解哈希这种说法, 但是编码就存在解码,加密就存在解密。

绝不要使用弱哈希或已被破解的哈希算法,像 MD5 或 SHA1 ,只使用强密码哈希算法。

绝不要以明文形式显示或发送密码,即使是对密码的所有者也应该这样。如果你需要 “忘记密码” 的功能,可以随机生成一个新的 一次性的(这点很重要)密码,然后把这个密码发送给用户。

(6)分布式session共享方案

方式优点缺点
session复制任何一个服务器上的 session 发生改变(增删改),该节点会把这个 session 的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要 session ,以此来保证 session 同步可容错,各个服务器间 session 能够实时响应会对网络负荷造成一定压力,如果 session 量大的话可能会造成网络堵塞,拖慢服务器性能
粘性 session /IP 绑定策略采用 Ngnix 中的 ip_hash 机制,将某个 ip的所有请求都定向到同一台服务器上,即将用户与服务器绑定。 用户第一次请求时,负载均衡器将用户的请求转发到了 A 服务器上,如果负载均衡器设置了粘性 session 的话,那么用户以后的每次请求都会转发到 A 服务器上,相当于把用户和 A 服务器粘到了一块,这就是粘性 session 机制。简单,不需要对 session 做任何处理缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的 session 信息都将失效
session 共享(常用)使用分布式缓存方案比如 Memcached 、Redis 来缓存 session,但是要求 Memcached 或 Redis 必须是集群1、实现了 session 共享;2、可以水平扩展(增加 Redis 服务器);3、服务器重启 session 不丢失(不过也要注意 session 在 Redis 中的刷新/失效机制);4、不仅可以跨服务器 session 共享,甚至可以跨平台(例如网页端和 APP 端)
session持久化将 session 存储到数据库中,保证 session 的持久化服务器出现问题,session 不会丢失如果网站的访问量很大,把 session 存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库

(7)防范重放攻击

重放攻击是计算机世界黑客常用的攻击方式之一,所谓重放攻击就是攻击者发送一个目的主机已接收过的包,来达到欺骗系统的目的,主要用于身份认证过程。 首先要明确一个事情,重放攻击是二次请求,黑客通过抓包获取到了请求的HTTP报文,然后黑客自己编写了一个类似的HTTP请求,发送给服务器。也就是说服务器处理了两个请求,先处理了正常的HTTP请求,然后又处理了黑客发送的篡改过的HTTP请求。

常用三种方式来防范,需要前后端做一些设计:

1、加随机数:该方法优点是认证双方不需要时间同步,双方记住使用过的随机数,如发现报文中有以前使用过的随机数,就认为是重放攻击。缺点是需要额外保存使用过的随机数,若记录的时间段较长,则保存和查询的开销较大。

2、加时间戳:该方法优点是不用额外保存其他信息。缺点是认证双方需要准确的时间同步,同步越好,受攻击的可能性就越小。但当系统很庞大,跨越的区域较广时,要做到精确的时间同步并不是很容易。

3、加流水号:就是双方在报文中添加一个逐步递增的整数,只要接收到一个不连续的流水号报文(太大或太小),就认定有重放威胁。该方法优点是不需要时间同步,保存的信息量比随机数方式小。缺点是一旦攻击者对报文解密成功,就可以获得流水号,从而每次将流水号递增欺骗认证端。

也可以简单的使用互斥ip、互斥设备识别码来进行防范。

2、Outh2与SAML

常用的SSO协议有两种:SAML和Outh2

2.1、SAML

SAML的全称是Security Assertion Markup Language, 是由OASIS制定的一套基于XML格式的开放标准,用在身份提供者(IdP)和服务提供者 (SP)之间交换身份验证和授权数据。

SAML的一个非常重要的应用就是基于Web的单点登录(SSO)。

在SAML协议中定义了三个角色,分别是principal:代表主体通常表示人类用户。identity provider (IdP)身份提供者和service provider (SP)服务提供者。

IdP的作用就是进行身份认证,并且将用户的认证信息和授权信息传递给服务提供者。

SP的作用就是进行用户认证信息的验证,并且授权用户访问指定的资源信息。

图片.png

(1)用户转到服务提供商并单击 SAML 登录
(2)SP 将请求重定向到身份提供者
(3)身份提供者向用户显示登录页面以输入凭据
(4)输入凭据后,SAML IdP 会验证其 Active Directory 或数据库中的凭据
(5)验证后,SAML 响应会以 XML 格式发送带有断言,如上所示
(6)然后用户将登录到应用程序

<form method="post" action="https://sp.flydean.com/SAML2/SSO/POST" ... >
    <input type="hidden" name="SAMLResponse" value="response" />
    <input type="hidden" name="RelayState" value="token" />
    ...
    <input type="submit" value="Submit" />
</form>

这个form中包含了SAMLResponse信息,SAMLResponse中包含了用户相关的信息,samlp:Response中也包含有saml:Assertion信息。

注意,用户登录成功后,Idp向Sp返回SAML Assertion,并且将用户重定向到 SP,这一步通常有两种做法:

①HTTP 重定向(HTTP Redirect):这并不推荐,应为重定向的 URL 长度有限,无法携带更长的信息,比如 SMAL Token;

②HTTP POST 请求:这个是更常规的做法,当用户登陆完毕之后渲染出一个表单,用户点击后向 SP 提交 POST 请求。又或者可以使用 Javascript 向 SP 发出一个 POST 请求;

这里又引申出一个问题,使用第②种方法的时候,在web中是没有问题的,但是在基于移动平台(android或ios等)上,应用跳转至 Safari 浏览器,在登陆认证完毕之后,需要通过 HTTP POST 的形式将 token 返回至手机应用,这就需要POST的URL拉起应用。现在的一般做法是,应用通常是hybird架构,IdP 授权阶段不跳转至系统的 Safari 浏览器,在内嵌的 webview 中解决,在想方设法从 webview 中提取 token。无论如何,SAML 2.0 并不适用于当下跨平台的场景,这也许与它产生的年代也有关系。

2.2、Outh2/OIDC

图片.png

Outh2流与OIDC集成:

图片.png

2.3、对比

特点优点缺点
SAML认证协议 SAML 2.0 是一个开放标准,用于在主体、服务提供者和身份提供者这三个参与者之间传递身份验证和授权信息。所有的信息交换都是由前端浏览器来完成的,在SP和IdP之间不存在直接的通信。如果为了提高安全性,也可以使用引用消息。也就是说IdP返回的不是直接的SAML assertion,而是一个SAML assertion的引用。SP收到这个引用之后,可以从后台再去查询真实的SAML assertion,从而提高了安全性。1、协议流非常简单,所有的消息都是简单的GET或者POST请求1、移动端上如果app仅支持URL的启动链接,name可能获取不到HTTP POST的body内容,或者进行一些改造
Outh2授权协议 OAuth 是一种开放式授权标准,通过访问令牌授予对应用程序、设备、应用程序编程接口 (API) 和服务器的安全委托访问权限。OAuth 授权应用程序访问您的数据,而无需授予它访问您的凭据的权限。1、弥补 SAML 在移动平台上的不足,并且基于JSON而不是 XML。2、OAuth2 广泛使用 JWT 令牌,因此比 SAML 更轻、更快。3、1和2的原因,OAuth2 最适合用户体验,因为它在移动设备上运行良好,会话短、消息轻。4、Outh2适合临时访问5、脱离了平台,而是关注协议本身来实现SSO。1、OAuth2并没有指定Resource Server怎么和Authorization Server进行交互。也没有规定返回用户信息的内容和格式。这些都需要实现方自己去决定。2、OAuth2默认是在HTTPS环境下工作的,所以并没有约定信息的加密方式。我们需要自己去实现
openID connect(OIDC)认证协议 OpenID Connect基于 OpenID分散式身份验证协议,在 OAuth 2.0 之上提供了一个身份验证层。它解决了 OAuth 中缺乏身份验证机制的问题,这在授权敏感交易(如支付)时是一个弱点。同上

SAML token中已经包含了用户身份信息,但是在OAuth2,在拿到token之后,需要额外再做一次对该token的校验;

OAuth2因为需要再做一次认证,所以可以在 Authorization Server 端对token进行无效处理