Authentication

Fc04dB Lv4

# 鉴权(Authentication)

鉴权是指验证用户是否拥有访问系统的权利。传统的鉴权是通过密码来验证的。这种方式的前提是,每个获得密码的用户都已经被授权。这种方式的弱点十分明显:一旦密码被偷或用户遗失密码,情况就会十分麻烦,需要管理员对用户密码进行重新修改,而修改密码之前还要人工验证用户的合法身份。

image-20240717171243051

主要鉴权的方法

  • HTTP Basic Authentication
  • Session-Cookie
  • Token
  • OAuth
  • LDAP

另外还有一些基于基本认证方式搭建的鉴权体系,比如 SSO JWT

# HTTP Basic Authentication

HTTP Basic Authentication 通过在 HTTP 请求头中传递用户的用户名和密码进行身份验证

1. 客户端请求访问受保护的资源:客户端尝试访问服务器上的受保护资源。

1
2
GET /protected-resource HTTP/1.1
Host: example.com

2. 服务器响应 401 未授权状态码:服务器响应一个 401 未授权状态码,并在响应头中包含一个 WWW-Authenticate 头,提示客户端需要进行 Basic 认证。

1
2
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="Access to the protected resource"

3. 客户端提供凭证:客户端接收到 401 响应后,会在后续请求的头部添加一个 Authorization 头,包含 Base64 编码的用户名和密码。

1
2
3
GET /protected-resource HTTP/1.1
Host: example.com
Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l

4. 服务器验证凭证:服务器解码并验证用户名和密码,如果验证成功,则允许访问资源,否则返回 401 未授权状态码。

虽然 HTTP Basic Authentication 简单易用,但由于凭证是以 Base64 编码的形式传输的,未经加密,存在一定的安全风险:

  • 中间人攻击(MITM):在未加密的 HTTP 连接中,攻击者可以轻易截获和解码凭证。
  • 重放攻击:攻击者可以捕获并重放请求,冒充合法用户访问资源。

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

1
2
3
4
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

设定 Cookie 时可以设定一些参数, Expires 过期时间, Secure HttpOnly 限制访问, Domain Path 定义 Cookie 作用域, SameSite 设置跨站发送限制,还有 __Host-__Secure- 前缀用于断言特定事实

主要有三方面功能:

  • 会话状态管理 如用户登录状态、购物车、游戏分数或其他需要记录的信息
  • 个性化设置 如用户自定义设置、主题和其他设置
  • 浏览器行为跟踪 如跟踪分析用户行为等

# Session

  1. 服务端在接收到来自客户端的首次访问时,会自动创建 Session(将 Session 保存在内存中,也可以保存在 Redis 中),然后给这个 Session 生成一个唯一的标识字符串会话身份凭证 session_id (即 sid ),并在响应头 Set-Cookie 中设置这个唯一标识符
  2. (非必须)签名,对 sid 进行加密处理,服务端会根据这个 secret 密钥进行解密
  3. 浏览器收到请求响应后会解析响应头,并自动将 sid 保存在本地 Cookie 中,浏览器在下次 HTTP 请求时请求头会自动附带上该域名下的 Cookie 信息
  4. 服务端在接收客户端请求时会去解析请求头 Cookie 中的 sid ,然后根据这个 sid 去找服务端保存的该客户端的 sid ,然后判断该请求是否合法
  5. 一旦用户登出,服务端和浏览器将会同时销毁各自保存的会话 ID,服务端会根据数据库验证会话身份凭证,如果验证通过,则继续处理

session-cookie

1、存储位置不同

cookie 的数据信息存放在客户端浏览器上。

session 的数据信息存放在服务器上。

2、存储容量不同

单个 cookie 保存的数据 <=4KB,一个站点最多保存 20 个 Cookie。

对于 session 来说并没有上限,但出于对服务器端的性能考虑,session 内不要存放过多的东西,并且设置 session 删除机制。

3、存储方式不同

cookie 中只能保管 ASCII 字符串,并需要通过编码方式存储为 Unicode 字符或者二进制数据。

session 中能够存储任何类型的数据,包括且不限于 string,integer,list,map 等。

4、隐私策略不同

cookie 对客户端是可见的,别有用心的人可以分析存放在本地的 cookie 并进行 cookie 欺骗,所以它是不安全的。

session 存储在服务器上,对客户端是透明对,不存在敏感信息泄漏的风险。

5、有效期上不同

开发可以通过设置 cookie 的属性,达到使 cookie 长期有效的效果。

session 依赖于名为 JSESSIONID 的 cookie,而 cookie JSESSIONID 的过期时间默认为 - 1,只需关闭窗口该 session 就会失效,因而 session 不能达到长期有效的效果。

6、服务器压力不同

cookie 保管在客户端,不占用服务器资源。对于并发用户十分多的网站,cookie 是很好的选择。

session 是保管在服务器端的,每个用户都会产生一个 session。假如并发访问的用户十分多,会产生十分多的 session,耗费大量的内存。

7、浏览器支持不同

假如客户端浏览器不支持 cookie: cookie 是需要客户端浏览器支持的,假如客户端禁用了 cookie,或者不支持 cookie,则会话跟踪会失效。关于 WAP 上的应用,常规的 cookie 就派不上用场了。

运用 session 需要使用 URL 地址重写的方式。一切用到 session 程序的 URL 都要进行 URL 地址重写,否则 session 会话跟踪还会失效。

# Token

很多公有 API 和开发框架的内部 API 调用都是基于 Token 认证

Token 和 Session-Cookie 认证方式中的 Session ID 不同,并非只是一个标识符。Token 一般会包含用户的相关信息,通过验证 Token 不仅可以完成身份校验,还可以获取预设的信息

流程中的主要特点:

  1. Token 储存在客户端
  2. 后续 Token 被附带于 Authorization 字段中,
  3. 客户端负责校验 Token 的结构内容是否符合要求

Token

优点:服务端无状态,无需访问远程访问或数据库,支持跨域跨程序调用,可以有效避免 CSRF(无 cookie)

缺点:更大占带宽,需要解密消耗性能

Session-Cookie 认证仅仅靠的是 sid 这个生成的唯一标识符,服务端需要根据客户端传来的 sid 查询保存在服务端 Session 里保存的登录状态,当存储的信息数据量超过一定量时会影响服务端的处理效能。而且 Session-Cookie 认证需要靠浏览器的 Cookie 机制实现,如果遇到原生 NativeAPP 时这种机制就不起作用了,或是浏览器的 Cookie 存储功能被禁用,也是无法使用该认证机制实现鉴权的。

Token 认证机制特别的是,实质上登录状态是用户登录后存放在客户端的,服务端不会充当保存 用户信息凭证 的角色,当每次客户端请求时附带该凭证,只要服务端根据定义的规则校验是否匹配和合法即可,客户端存储的手段也不限于 Cookie,可以使用 Web Storage 等其他缓存方式。

简单来说,Session-Cookie 机制限制了客户端的类型,而 Token 验证机制丰富了客户端类型。而且 Token 机制更像是一种框架,可供用户更灵活地构建鉴权微服务

# OAuth

OAuth(开放授权)是一个开发标准,允许用户授权 第三方网站 访问他们存储在另外的服务提供商中的信息,而不需要接触到用户名和密码。为了保护数据的安全和隐私,第三方网站访问用户数据前都需要 显式地向用户征求授权。我们常见的 OAuth 认证服务的厂商有微信、QQ、支付宝等。

OAuth 协议又有 1.0 和 2.0 两个版本,2.0 版整个授权验证流程更简单更安全,也是目前最主要的用户身份验证和授权方式。

应用场景有:第三方应用的接入、微服务鉴权互信、接入第三方平台、第一方密码登录等

理解 OAuth 2.0 - 阮一峰的网络日志 (ruanyifeng.com)

# LDAP

轻量目录访问协议 Lightweight Directory Access Protocol ,一个开放、广泛被使用的工业标准(IEFT、RFC)。企业级软件也通常具备 * 支持 LDAP- 的功能,比如 Jira、Confluence、OpenVPN 等,企业也经常采用 LDAP 服务器来作为企业的认证源和数据源。

它的主要功能点或场景:

  • 作为数据源它可以用于存储
    • 企业的组织架构树
    • 企业员工信息
    • 证书信息
    • 会议室,打印机等等资源
  • 作为认证源,它也有多种用途
    • 存储用户的密码
    • 对外提供 LDAP 协议的认证方式(通过 LDAP BIND 协议来校验用户名和密码)
    • 密码策略(密码复杂度,历史密码记录,用户锁定等等)

# SSO

实际就是利用 Session-Cookie 的特性

当存在两个相同域名下的系统 A a.abc.com 和系统 B b.abc.com 时,以下为他们实现 SSO 的步骤:

  1. 用户访问某个子系统时(例如 a.abc.com ),如果没有登录,则跳转至 SSO 认证中心提供的登录页面进行登录
  2. 登录认证后,服务端把登录用户的信息存储于 Session 中,并为用户生成对应的会话身份凭证附加在响应头的 Set-Cookie 字段中,随着请求返回写入浏览器中,并回跳到设定的子系统链接中
  3. 下次发送请求时,当用户访问同域名的系统 B 时,由于 A 和 B 在相同域名下,也是 abc.com ,浏览器会自动带上之前的 Cookie。此时服务端就可以通过该 Cookie 来验证登录状态了。

# 跨域 SSO(CAS)

其实这个才是 SSO 的标准实现,基于 CAS

CAS(Central Authentication Service)中央授权服务,本身是一个开源协议,分为 1.0 版本和 2.0 版本。1.0 称为基础模式,2.0 称为代理模式,适用于存在非 Web 应用之间的单点登录。

jwt-cas

一篇文章彻底弄懂 CAS 实现 SSO 单点登录原理 - Hi,王松柏 - 博客园 (cnblogs.com)

# ⭐ JWT

JSON Web Token (JWT) 是一个开放标准 (RFC 7519) ,它定义了一种紧凑和自包含的方式, 用于作为 JSON 对象在各方之间安全地传输信息。此信息可以进行验证和信任,因为它是经过数字签名的。JWT 可以使用机密 (使用 HMAC 算法) 或使用 RSA 或 ECDSA 的公钥 / 私钥对进行签名。
虽然可以对 JWT 进行加密,以便在各方之间提供保密性,但是我们将关注已签名的 Token。签名 Token 可以验证其中包含的声明的完整性,而加密 Token 可以向其他方隐藏这些声明。当使用公钥 / 私钥对对令牌进行签名时,该签名还证明只有持有私钥的一方才是对其进行签名的一方 ( 签名技术是保证传输的信息不被篡改,并不能保证信息传输的安全 )。

# JWT 的结构

  • Header
  • Payload
  • Signature

类似于 xxxx.xxxx.xxxx 格式,真实情况如下:

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQss
# 头部

由类型 JWT 和加密形式构成

json

1
2
3
4
{
"alg": "HS256",
"typ": "JWT"
}

然后头部会被 Base64URL 加密

# 载荷

因为可以被直接解密,所以存放一些不敏感信息

json

1
2
3
4
5
6
7
8
9
{
"iss": "Jehoshaphat Tse",
"iat": 1441593502,
"exp": 1441594722,
"aud": "www.example.com",
"sub": "mrsingsing@example.com",
"name": "John Doe",
"admin": true
}

这里面的前五个字段都是由 JWT 的标准所定义的,所谓 Registered claims

  • iss :该 JWT 的签发者
  • sub :该 JWT 所面向的用户
  • aud :接收该 JWT 的一方
  • exp (expires):什么时候过期,这是 Unix 时间戳
  • iat (issued at):在什么时候签发的。

然后载荷会被 Base64URL 加密

# 签名

把头部和载荷加密拼接后用之前确定的加密方式和 secret 进行签名,拼接在最后

1
2
3
4
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

image-20240717174546213

JSON Web Tokens - jwt.io

JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

1
2
3
4
5
{
"姓名": "张三",
"角色": "管理员",
"到期时间": "2018年7月1日0点0分"
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。

服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

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

此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息 Authorization 字段里面。

1
Authorization: Bearer <token>

另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。

# 几个特点

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

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

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

(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此 ** 无法在使用过程中废止某个 token,或者更改 token 的权限。** 也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。

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

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

# 鉴权绕过

# 经典的 Shiro

Shiro 鉴权绕过

  • Title: Authentication
  • Author: Fc04dB
  • Created at : 2024-07-17 17:06:22
  • Updated at : 2024-08-28 14:50:52
  • Link: https://redefine.ohevan.com/2024/07/17/Authentication/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments