阅读这篇文档你可以了解到一些常见的认证方式及其优缺点,在实际场景中该如何去搭配各种认证方式。
Terminology
了解 Authorization 前,需要先了解以下术语
认证(Authentication )
认证是对身份的一种确认过程;也可以说是身份有效性的确认;Are you who you say you are?
授权(Authorization)
授权是指对行为或资源允许的过程;Are you allowed to do this action?
对应的是鉴权,是对行为或资源是否允许的确认过程
The User: "Resource Owner"
资源的拥有者,一般都是用户自己
The Authorization Server
资源的认证服务器,提供 Authorization Endpoint 及 Token endpoint
Authorization Endpoint
请求 authorization API
Token Endpoint
请求 access_token API
The API: "Resource Server"
资源服务器,具体的 Service 上的 API
The Third-Party Application: "Client"
需要申请访问资源的应用,可以是 APP、JS APP、Server 等
Token Types
Access token
Access token 是由 Authorization Server 通过安全认证后,生成临时用于访问 Resource 的凭证;
JWT 就是一种具体的实现方式.
可以标识身份;
也可以是 self-contain 认证权限信息;
一般有效期较短;
用于 Resource Server 的请求中
JWT
可以参考JWT,
有个使用中的小问题,记录下
Base64URL 与 Base64 算法
Base64 有三个字符+、/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ 。这就是 Base64URL 算法。JWT 会使用 Base64URL 编码的,主要是考虑到一般 jwt Token 会直接被放在 URL 上。
Refresh token
Refresh token 是由 Authorization Server 通过安全认证后,生成用于长时间内获取 access_token 的凭证;
仅用于 Authorization Server 的请求中(不可传输给其他服务);
若 access_token expire 了,则使用 Refresh token 去 Authorization Server 重新获取;
refresh token 可以管理 access token,防止 access_token 被多个 client 使用;
"bearer" token type
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer mF_9.B5f-4.1JqM
"mac" token type
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: MAC id="h480djs93hd8",
nonce="274312:dj83hs9s",
mac="kDZvddkndxvhGRXZhvuDjEWhGeE="
Access token 与 Refresh token 认证的机制
client 向 AS 发起 Token Request ;
AS 响应返回 access_token 即 refresh_token;
client 携带 access_token 去资源服务器请求资源;
资源服务器响应返回有权限的资源(未请求 AS,说明 access_token 是 self-contain 权限信息的);
access_token 失效后返回 error,并 skip 到 G
-
client 携带 refresh_token 向 AS 请求新的 access_token;
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
AS 认证通过后返回 refresh_token 及新的 access_token;
Authorization Types
API Keys
该方式在调用 API 前需要先在该 API Provider 那申请一个(对)API key,如 APPID 和 APPSecret,在请求的过程中在 query 或 header 中加上这个(对)API key;其中 APPSecret 一般都是在 Server-to-Server 的场景中使用,而 APPID 可通过终端 JS 传递到后端服务器,然后获取内存中的 APPSecret,一起放在 query 或 header 中转发到 API 服务;
图中因为仅考虑认证的机理。
优点:
这种认证模式的好处就是简单且能识别 API 调用者的身份;
有 APPSecret,所以一般都是在 Server-to-Server 的场景中使用;
Basic Auth
该方式其实就是采用了 base64 对 username 及 password 进行混淆编码后放在 header 中,形如
Authorization: Basic YW50ejoxMjM0NTY=
在Server端解码后得到
antz:123456
该方式比较简单,但是如果在互联网传输,那么需要保证协议是 https 的,防止被拦截解码获取明文。
HMAC (Hash-based message authorization code)
该方式是一种更高级别、更安全的授权方式,API provider 与 API caller 事先约定一个 Secret Key 及算法,然后保证只有双方知道,Caller 在调用 API 时,按照双方规定的算法对请求进行签名,得到 signature,并将该 signature 一并发到 Server 端,Server 端同理对请求进行签名,也得出一个 signature,然后对比两个 signature 是否 match,match 则认证通过,否则拒绝;
该方式重点就是在保存 Secret Key,所以一般 Web 或能直接查看到 JS 源码的场景都不适用;一般在 IOS、Android 等 Native 应用中使用场景较多;
优点:
- 能够标识身份,确认调用者;
- 防止请求信息被篡改;
OAuth 2.0
OAuth2.0 主要是解决了在互联网上 Resource Owner 与 Client Application、third-parties 访问数据安全的问题。提供了一套安全的认证标准。
Authorization Code
该认证方式是一种较安全的认证方式(虽然流程看起来复杂),其中主要是涉及到两个步骤一个是授权服务请求 authorization 过程,另一个是 Application client 请求 access_token 过程(这里有 CORS 问题,所以 Authorization Server CORS 必须是 allow 的),在网上找到以下图,完美使用了 Authorization Code 的认证方式;
解析
- APP_XYZ 是 Client Application 的角色,需要事先在 ABC 的 Authorization Server 上注册并填写 default 的 redirect_url;同时 Authorization Server 会自动分配 client_id 和 client_secret;
- Request Authorization 阶段:在图中的 ② 步骤是初次请求 Authorization Code 的过程,
初次请求的条件参数
response_type:在Authorization Code的Grant Type模式下,必须是code
client_id:APP_XYZ的client_id
redirect_url:也是认证成功后callback URL,有文档说这个redirect_url与注册时的redirect_url要一致;
https://authorization-server.com/oauth2/authorize?response_type=code&
client_id=0rhQErXIdfasdf8087ck9df0099&
redirect_uri=https://mycallback.com
-
在图中的 ⑥ 步骤是认证成功后 redirect_url,同时会返回 Authorization Code
形如https://mycallback.com/?code=dfg34fd4cad58c66d0a5edfad8952
Request Token 阶段:在图中的 ⑦ 步骤是 Client Application 请求 access_token 的过程,该需要将 ⑥ 中获得的 Authorization Code 及 client_id、client_secret 等一起发给 token endpoint;其中 client_id 和 client_sercet 在 https 下采用 Http Basic 的认证方式发送给 token endpoint;
请求的参数
grant_type:authorization_code
code:上一次认证返回的code
redirect_uri:保持与初次请求authorization的一致
client_id:APP_XYZ的client_id
client_secret:APP_XYZ的client_secret
curl -v –k -X POST --basic
-u 0rhQErXIdfasdf8087ck9df0:1232kL756W8usQaVNgCNk454z9C2D0a
-H "Content-Type:application/x-www-form-urlencoded;charset=UTF-8"
-d "grant_type=authorization_code&
code=dfg34fd4cad58c66d0a5edfad8952&
redirect_uri=https://mycallback.com
- 在图中的 ⑧ 步骤是请求 token 成功后返回 access_token
{
"token_type":"bearer",
"expires_in":3600, //对access_token有效
"refresh_token":"gdfg6c2d6fghhj67345d5c4ef6bhghgf6",
"access_token":"cdfdfe1d29e4dffhrt4073dbtygh"
}
虽然目前 Authorization Code 的方式还是使用的比较多,但据 APP 开发童靴了解到,在 APP 端恶意的 APP 的确能拦截到 Authorization Endpoint 的响应,获取到 code,然后去获取 access_token 的问题。具体的问题可参考 IETF,感兴趣童鞋可搜索【IOS 逆向安全】相关话题。
PKCE
下图是 Authorization Code 认证方式扩展后的认证方式即 PKCE,主要差异有两点:
- 在 Request Authorization 阶段,为了使获取 token 阶段更安全可靠,此处增加了 code_challenge 和 code_challenge_method 两个参数,其中 code_challenge 是 code_verifier 经过 code_challenge_method 加密编码后的密文;另一个 code_challenge_method 就是加密的方法(算法),IETF 规定 code_challenge_method 是非必须参数,若不传,则 code_challenge 就是明文;若传 S256(SHA256)增加表示采用该算法计算 code_verifier 得出 code_challenge,具体这一块逻辑可参考 IETF;
-
在 Request Token 阶段,增加了 code_verifier 字段,Authorization Server 会拿到该值,使用 code_challenge_method 计算得出 code_challenge,与之前传过来的 code_challenge 做匹配。
Implicit Grant Type(不推荐)
该方式是一种 Authorization Code 的简化后的认证方式,它将交换 Authorization Code 请求直接简化(删除),Application Client 直接携带 client_id 去发起 request access_token 的请求,即省略了图中的 ⑥⑦ 步骤,直接跳到 ⑧ 返回 access_token。
【前世今生】
该方式最初是为了给 Native APP 和 JS APP 使用的,它所出现的原因是因为最初浏览器有 CORS 的困扰,POST 请求只能在同 domain 下访问 Authorization Server(见图中 ⑤ 输入账号密码后向自己的 AuthorizationServer 请求认证)而 ⑦ 步骤是 POST 请求且跨域,无法实现,所以省略了 ⑥⑦ 步骤,是一种妥协的方案;而如今 CORS 已不是什么问题,只要 Server 允许就可以访问,但现在已经推荐使用 PKCE 的方式去实现。
authorization 请求
https://authorization-server.com/oauth2/authorize?
response_type=token&
client_id=324349svVYoXJGt05654345&
redirect_uri=https://mycallback.com
response
https://mycallback.com/#access_token=1235bf6d844342344654563fgdfg&ex
pires_in=3600
其 response 仅仅是采用了 access_token
IETF 规定 Authorization Server 上 Authorization Endpoint 必须同时支持 POST 和 GET 请求,而 Token Endpoint 必须仅支持 POST 请求。
Resource Owner Password Credentials Grant Type
认证流程,如图
逻辑相对较简单,对于用户而言,基本没有授权可言(可能用户就不知道有后面这一步)。
2 中请求
curl -v -k -X POST --basic
-u 0rhQErXIdfasdf8087ck9df0:1232kL756W8usQaVNgCNk454z9C2D0a
-H "Content-Type:application/x-www-form-urlencoded;charset=UTF-8"
-d "grant_type=password&
username=admin&password=admin"
https://authorization.com/oauth2/token
response
{
"token_type":"bearer",
"expires_in":685,"
"refresh_token":"123157546b343dff0165c4ef6b3f736",
"access_token":"asdfa3e1d29e45b35657gsdfg84073dbfbgfdgs"
}
Client Credentials Grant Type
认证流程,如图,该认证方式一般在安全可信且是 https 的 server-to-server 场景中使用
1 中请求
curl –v –k -X POST --basic
-u 0rhQErXIdfasdf8087ck9df0:1232kL756W8usQaVNgCNk454z9C2D0a
-H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8"
-d "grant_type=client_credentials"
https://authorization.com/oauth2/token
response
{
"token_type":"bearer",
"expires_in":3600,
"access_token":"4c9a9ae7463ff9bb93ae7f169bd6a"
}
其他认证
AK/SK 认证(HMAC )
目前在国内大部分云厂商都是采用 AK/SK 的认证模式;一般都是先在云厂商平台注册应用,并生成一对 access key 和 access secret,然后对请求参数及其它按照云厂商提供的算法生成签名,签名与 access key 一起发送到服务器端,然后使用相同的算法生成签名,比较。这种方式相对其它的认证方式会更安全,一般使用场景是在 machine-to-machine(M2M),保证了 access secret 不会被泄露且不会在网络中传输,一般情况下生成签名的算法也都是不可逆的,所以即使被拦截也无法篡改数据;
大致描述了 AK/SK 的简单过程,signature 的算法也可以参考该地址
可以与 HMAC 进行对比下,可能会发现比较相似,可以认为是升级版。
- M2M 的使用场景,保证 access secret 不会被泄露,建议定期更换;
- 采用签名的机制,算法不可逆,防止数据被篡改;
请求中带有 timestamp 的作用是,可保证请求在一段时间内有效,AS 服务端需要校验 timestamp,可实现防重放攻击;
如何去选择认证方式,需要考虑的点
- 判断你的 application 是 User-to-Machine(U2M)还是 Machine-to-Machine(M2M);U2M 一般认为是不可信的 client,那么你的 secret 就不能存储在 client,同时一般情况下是需要有 user 资源需要去授权,那么可以从 OAuth 2.0 中 Authorization Code 或 PKCE 的认证方式进行选择;对于 M2M,它是可信的 client,一般 secret 不容易被泄露,所以可以将采用 HMAC、Http Basic Auth 等认证方式+Https 基本可以做到认证的效果,当然还可以采用更安全的 AK/SK 的方式。
- 可以从需要认证 scope 出发,比如说就是为了做身份认证,那么认证方式就可以选择简单一点的,比如 Http Basic;再比如说要做防篡改等,就采用更高级一点的;
- 考虑 access token 的选择,日常开发中 token 还是比较常见的,过去我们开发中用的无状态的 token,它仅仅是个标识,还有现在比较流行的 JWT,自包含型的 token,减轻服务的压力,看上去还是比较 nice 的(但是目前貌似没有看到有大网站在使用?)。
最后推荐一个网站,需要设计 Authorization Portal 的可以参考一波。
Reference
https://aaronparecki.com/oauth-2-simplified/
https://tools.ietf.org/html/rfc7636#section-1.1 PKCE
https://www.ibm.com/support/knowledgecenter/zh/SSPREK_9.0.4/com.ibm.isam.doc/config/concept/oauth_pkce.html PKCE
https://oauth.net/2/ OAuth
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS CORS
https://tools.ietf.org/html/rfc6749#page-21 Token Endpoint 及 Authorization Endpoint
https://support.huaweicloud.com/devg-apisign/api-sign-algorithm.html AK/SK
https://juejin.im/post/5c9ada58e51d453fea4a99bc