oAuth协议
作者:互联网
oAuth协议
大纲:oAuth协议是什么?可以用在什么地方?最新的2.1版本有了什么更新变化?
简单介绍
协议很多,oAuth是什么?
OAUTH,即Web 授权协议(Web Authorization Protocol)。该协议允许用户授予第三方网站或应用程序访问用户受保护资源的权限,而不必透露他们的长期凭据,甚至他们的身份(账号密码)。
与以往的用户资源授权方式不同的是,OAUTH的授权不会使第三方触及到用户的帐号信息(如用户名与密码)。即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权。因此OAUTH是安全的。
OAUTH协议,已经在全世界得到广泛应用。在网页,APP,小程序等都有应用(微信等等)
而在我们的项目之中,也有可以运用的可能——比如添加微信登陆功能
协议特点
(1). 简单:不管是OAUTH服务提供者还是应用开发者,都很易于理解与使用;
(2). 安全:没有涉及到用户密钥等信息,更安全更灵活;
(3). 开放:任何服务提供商都可以实现OAUTH,任何软件开发商都可以使用OAUTH;
使用场景
由于服务A与服务B是由两家不同的服务提供商提供的,所以用户在这两家服务提供商的网站上各自注册了两个用户。
假设这两个用户名各不相同,密码也各不相同。
当用户要使用服务B打印存储在服务A上的文件时,用户该如何处理?
如果没有 OAuth 2.0,传统的做法是用户把账号信息进行分享。这听起来就十分傻,也存在许多安全隐患:
(1)"云冲印"为了后续的服务,会保存用户的密码,这样很不安全。只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。
(2)"云冲印"拥有了获取用户储存在A所有资料的权力,用户没法限制"云冲印"获得授权的范围和有效期。
(3)用户只有修改密码,才能收回赋予"云冲印"的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。
OAuth核心思想
1.让A与用户建立确认的关系。用户确认A,A确认用户
2.在“客户端”与“服务提供商”之间设置了一个授权层(authorization layer)。
1.“第三方”无法直接登录“服务提供商”,但可以登录此“授权层”
2.登录“授权层”时使用令牌 Token,该令牌与账号密码不同,拥有特定的权限范围与授权时间
3."第三方"登录授权层以后,"服务提供商"根据令牌的权限范围和有效期,向"客户端"开放用户储存的资料。
运行流程
OAuth 2.0 定义了以下 4 种授权模式:
-
授权码模式(authorization code)
-
简化模式(implicit)
-
密码模式(resource owner password credentials)
-
客户端模式(client credentials)
微信使用的是授权码模式(authorization code)。后面三者在2.1最新版里已经不推荐使用(不支持)。
授权码模式
授权码模式(authorization code)是功能最完整、流程最严密的授权模式。
它的特点就是通过客户端的后台服务器,与"服务提供商"的认证服务器进行互动。
步骤如下:
访问令牌(access token) 访问令牌是用于访问受保护资源的凭据,颁发给授权的客户端。该字符串通常对客户端不透明。令牌代表特定的访问范围和持续时间,由资源所有者授予,并由资源服务器和授权服务器执行。 刷新令牌(refresh token) 刷新令牌是用于获取访问令牌的凭据。刷新令牌由授权服务器颁发给客户端,用于在当前访问令牌失效或过期时获取新的访问令牌,或获取具有相同或更窄范围的附加访问令牌(访问令牌可能具有更短的范围)
A 步骤中,一些参数与信息:
redirect_uri:
应用开发者预先在申请应用时填写的地址,主要用于:当验证通过时,需要返回的页面,比如我开发的应用有一个登录成功的首页,那么用户在授权验证通过后,要回到我的应用的这个首页,那么这个首页的地址就是回调地址
state:
也就是需要传到我的应用首页的参数,这个参数在经过授权服务器(新浪微博)时会原封不动的传给回调地址,可不用。开发者可以用这个参数验证请求有效性。
返回数据
response_type为token
返回值字段 | 字段类型 | 字段说明 |
---|---|---|
access_token | string | 用来调用其它接口的授权过的accesstoken。 |
expires_in | string | accesstoken有效期时间,unix的timestamp格式。 |
refresh_token | string | 刷新token,如果有获取权限则返回。 |
state | string | 如果传递参数,会回传该参数。 |
微信的例子:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
服务器回应客户端的 URI,来自认证服务器的 HTTP 回复
E 步骤中,认证服务器发送的 HTTP 回复,包含以下参数:
如微信的返回:
{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }
Refresh的过程
以微信公众号为例子
公众号的微信网页授权是通过OAuth2.0机制实现的:
1.用户关注微信公众账号。
2.微信公众账号提供用户请求授权页面URL。
3.用户点击授权页面URL,将向服务器发起请求
4.服务器询问用户是否同意授权给微信公众账号
5.用户同意(scope为snsapi_base时无此步骤)
6.服务器将CODE通过回调传给微信公众账号
7.微信公众账号获得CODE
8.微信公众账号通过CODE向服务器请求Access Token
9.服务器返回Access Token和OpenID给微信公众账号
10.微信公众账号通过Access Token向服务器请求用户信息
11.服务器将用户信息回送给微信公众账号
android_app OAUTH 2.0 demo
一个可参考的android demo
解读某OAuth 2.0的开源示例android-oauth-app_Maxwell-CSDN博客_oauth2.0 开源
OAuth 2.1的更新
简单点说就是:
-
PKCE(安全机制)变成必须的了
-
Redrect URI的检查更严格
-
password, implicit模式都不再推荐使用(甚至不再支持)
-
不再允许通过URL查询参数传递access_token(甚至不再支持)
-
刷新token增加约束限制(如一次性刷新)
推荐(必须)使用 Authorization Code + PKCE
OAuth 2.0 公共客户端容易受到授权码拦截攻击(客户端本身没有能力保存密钥信息, 比如桌面软件, 手机App, 单页面程序)。 在此攻击中,攻击者在不受传输层安全 (TLS) 保护的通信路径中拦截从授权端点返回的授权代码,例如客户端操作系统内的应用程序间通信。一旦攻击者获得了对授权码的访问权限,它就可以 使用它来获取访问令牌。 ——OAuth 2.0 安全最佳实践
对第四步的解释。首先,重定向的URI,它起到一个类似“唤起”的作用,系统根据URI的scheme唤起相应App,如果恶意App注册了相同的scheme就能轻易拿到code;其次,URI从系统浏览器传递到App的过程走的基本都是不安全通道,这也增加了传递过程中被截获的风险。
因为App没有浏览器那样的cookie支持,AAS没有session这样的东西来保存
state参数
从而防止CSRF,所以转而使用PKCE的code_verifier
和code_challenge
,顺便解决了无client_secret验证身份的问题。另外,用户侧也不推荐在App中嵌入Web页面,一个是增加用户识别的难度,另一个给了App访问Web隐私数据的机会。现在很多三方登录并不会提供嵌入式的页面,都是直接打开它们自己的App的单独登录界面,应该就是主要避免这个问题。
PKCE 解决了这一系列问题。 它的原理是客户端提供一个自创建的证明给授权服务器, 授权服务器通过它来验证客户端,把访问令牌(access_token) 颁发给真实的客户端而不是伪造的。
PKCE 在每次请求生成一个随机的密钥(code_verifier)。 第一次请求到授权服务器的 authorize endpoint时, 携带 code_challenge 和 code_challenge_method, 也就是 code_verifier 转换后的值和转换方法, 然后授权服务器需要把这两个参数缓存起来, 第二次请求到 token endpoint 时, 携带生成的随机密钥的原始值 (code_verifier)进行校验。
根据 OAuth 2.0 安全最佳实践(Security Best Current Practices) 2.1.1 章节
PKCE 协议:
本身是对 OAuth 2.0 的扩展, 它和之前的授权码流程大体上是一致的, 区别在于, 在向授权服务器的 authorize endpoint 请求时,需要额外的
code_challenge
和code_challenge_method
参数进行校验
对于外部请求的身份识别,现在较广泛的解决方案是AAS给App颁发一个事先约定的身份证明(如client_id
和client_secret
对),App将它们织入接口的请求(如签名),AAS以此确定请求合法。
然而新的问题又出现了,就是如何保证该身份证明本身的安全性。这个问题在移动端并没有完美的解决方案。
既然如此,OAUTH干脆不开放接口,而是要求App嵌入AAS自己的登录界面(与开放接口相比,AAS可借助界面实现一些安全策略比如在客户端判断请求频率是否超出阈值,请求是否由该页面发出/cookie判断)
....................
对Web应用程序来说,重定向的URI是属于client域的URL,而浏览器的安全级别也防止了其它进程对code的截获,且就算截获了,由于恶意进程不知道Client Credentials(存于client后端),也无法拿去交换AccessToken。而对于App,情况又变得错漏百出,如前所述,Client Credentials无法得到安全保障,而且code被拦截的风险也比Web端高了很多
使用 access_token 时, 不应该通过 URL 传递 token
根据 OAuth 2.0 安全最佳实践(Security Best Current Practices) 4.3.2 章节
在使用 access_token 时, 您不应该把token放到URL中, 第一, 浏览器地址栏本来就是暴露的, 第二, 可以查看浏览记录,找到 access_token。
正确的做法是, 把 access_token 放到 Http header 或者是 POST body 中。
刷新令牌 (Refresh Token) 应该是一次性的
根据 OAuth 2.0 安全最佳实践(Security Best Current Practices) 4.13.2 章节
access_token 访问令牌, refresh_token 刷新令牌, 刷新令牌可以在一段时间内获取访问令牌, 平衡了用户体验和安全性。在 OAuth 2.1 中, refresh_token 应该是一次性的, 用过后失效, 使用 refresh_token 获取access_token时, 还可以返回一个新的 refresh_token。
标签:协议,令牌,code,用户,token,服务器,oAuth,授权 来源: https://blog.csdn.net/lanhu9080/article/details/121665592