学习充电OAuth2.0安全设计之Authorization Code
Posted 柏维信息
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习充电OAuth2.0安全设计之Authorization Code相关的知识,希望对你有一定的参考价值。
OAuth 2.0 有 4 种认证流程:
-
授权码模式(authorization code) -
简化模式(implicit) -
密码模式(resource owner password credentials) -
客户端模式(client credentials)
下面以微信为例介绍最常见的也是最安全的 Authorization Code认证流程。
一、授权流程说明
微信OAuth2.0授权登录让微信用户使用微信身份安全登录第三方应用或网站,在微信用户授权登录已接入微信OAuth2.0的第三方应用后,第三方可以获取到用户的接口调用凭证(access_token),
通过access_token可以进行微信开放平台授权关系接口调用,从而可实现获取微信用户基本开放信息和帮助用户实现基础开放功能等。
微信OAuth2.0授权登录目前支持authorization_code模式,适用于拥有server端的应用授权。该模式整体流程为:
获取access_token时序图:
二、具体实现过程
下面具体介绍一下微信对这个协议的具体实现过程。
第1步:开发者在微信开放平台申请接入并成功获取到appid和AppSecret,并配置回调域名。
第2步:构造微信登录二维码的超链接如下:
https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
用户允许授权后,将会重定向到redirect_uri的网址上,并且带上code和state参数
redirect_uri?code=CODE&state=STATE
若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数
redirect_uri?state=STATE
实际抓包示例:
https://open.weixin.qq.com/connect/qrconnect?response_type=code&appid=wx2198c66352420194&redirect_uri=https%3A%2F%2Fpassform.test.com%2Fv3%2Fweb%2Flogin%2FwechatCallBack%3FisPc%3D1%26randomNum%3D%26redirect_uri%3Dhttps%253A%252F%252Fwww.test.com%252F%253Fopenid%253D33336839a7398ce8%26client_id%3D30&scope=snsapi_login&state=1614336736067
第3步:假如用户同意授权,在微信登录成功后会跳转到redirect_uri参数指定的URL,并在URL尾部追加code参数(即Authorization Code),如上述示例则会跳转到:
https://passform.test.com/v3/web/login/wechatCallBack?isPc=1&randomNum=&redirect_uri=https%3A%2F%2Fwww.test.com%2F%3Fopenid%3D33336839a7398ce8&client_id=30&code=053isZFa12PMAA0NVeGa1yR9300isZFe&state=1614336736067
然后,我们可以通过Authorization Code去获取用户openid和access_token,进而获得用户的信息。
第4步:通过Authorization Code获取Access Token和openid,服务器端构造如下请求即可获取Access Token和openid:
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
参数解释如下:
|
|
|
|
|
|
|
|
|
|
正确的返回:
{
"access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE",
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
参数说明:
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
错误返回样例:
{"errcode":40029,"errmsg":"invalid code"}
第5步:使用Access Token以及OpenID来访问用户数据
构造如下请求即可访问用户数据:
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
参数说明
|
|
|
---|---|---|
|
|
|
|
|
|
|
|
|
返回说明
正确的Json返回结果:
{
"openid":"OPENID",
"nickname":"NICKNAME",
"sex":1,
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
"privilege":[
"PRIVILEGE1",
"PRIVILEGE2"
],
"unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
错误的Json返回示例:
{
"errcode":40003,"errmsg":"invalid openid"
}
三、常见不安全设计造成的风险
风险1:redirect_uri回调域名欺骗
(1)未验证redirect_uri是否与注册的回调地址匹配
在上述实现的第二步中将redirect_uri修改为攻击者控制站点,用户在授权登录后将携带Authorization Code跳转到攻击者控制站点,攻击者从URL参数中即可获得Authorization Code并实现用户劫持。服务端必须验证client_id(APPID)和redirect_uri规定的域一致,如果不一致则无法登陆。
这样就防止了攻击者篡改redirect_uri为恶意站点的钓鱼攻击。
但是现在又提出了一种看似合理的绕过方法:
利用合法网站的URL重定向漏洞绕过redirect_uri中的域名白名单限制。
假设我有一个合法的网站whitehat.com,攻击者控制一个恶意站点hacker.com
攻击者可以构造这样一个链接来绕过redirect_uri中的域名白名单限制:
但是用户的授权令牌Authorization Code真的会被传送到hacker.com吗?
细心的人已经发现了,这个链接还是跳转到http://hacker.com/index.php而不是http://hacker.com/index.php?code=****
这是因为code参数前面的&符号没有URL编码,因此code参数被whitehat.com处理而不是属于Redirect参数的一部分。
因此,第一种攻击模型只能用来构造登录后的钓鱼攻击,通常情况下Authorization Code不会被传送到攻击者控制的站点中。
(2)未设置Authorization Code使用一次就失效
同时也给出了相应的安全建议:
即Authorization Code在获取后必须在短时间内失效而且只能被使用一次。这种方法在理论上确实可以有效的阻止上述的攻击方式,情景分析如下:
(1)攻击者构造恶意链接发送给用户,其中redirect_uri=http://bbs.test.com/index.php
(3)用户携带code向服务器发送请求加载此页面,加载的页面中含有攻击者放置的外链(例如头像中的图片链接等),用户加载外链中的图片,攻击者从referer消息头中获得用户的code
由于Authorization Code是通过redirect_uri浏览器回调传输,容易被截取,服务器生成的临时Authorization Code必须是一次有效,客户端使用一次后立即失效并且有效期很短,一般推荐30s有效期,可以保证临时Authorization Code被客户端正常消费后不会被再次使用。
比如构造一个认证请求,redirect_uri = http://app.com/test?callback=<script ></script>
服务器端需要对redirect_uri进行检查禁止特殊字符输入,并且对redirect_uri进行全匹配,不做模糊匹配可以杜绝XSS攻击。
风险3:未添加State 防止CSRF
第2步认证请求url中state参数是最容易被忽略的,大部分IDP不会强制要求客户端使用state参数。与 CSRF 攻击类似,如果 state 参数为空,作为攻击者,
1. 先申请一个新的,专门用于攻击他人的账号;
2. 然后走正常流程,跳到微信上去登录此账号;
3. 登录成功之后,微信带着 code 回跳到第三方站点,如www.test.com,这个时候,攻击者拦截自己的请求让他不再往下进行,而直接将带 code 的链接发给受害者,并欺骗受害者点击;
4. 受害人点击链接之后,继续攻击者账号的登录流程,不知不觉登录了攻击者的账号
受害者如果这个时候没察觉此账号不是他本人的,传了一些隐私文件,如照片啥的,攻击者立马就能通过自己的账号看到。
而 state 参数如果利用起来,当作 CSRF Token,就能避免此事的发生:
1. 攻击者依旧获取 code 并打算骗受害者点击
2. 受害者点击链接,但因服务器(比如 www.test.com)分配给受害者的设备的 state 值和链接里面的(分配给攻击者的)state 值不一样,服务器(test.com)直接返回验证 state 失败。
所以安全的实现是:
客户端每次请求生成唯一字符串在请求中放到state参数中,服务端认证成功返回Authorization Code会带上state参数,客户端验证state是否是自己生成的唯一串,可以确定这次请求是有客户端真实发出的,不是黑客伪造的请求
风险4:Access_Token泄露
由于Access_Token是通过http协议从服务器端传输给客户端,为了防止旁路监听泄露Access_Token,服务器必须提供https来保证传输通道的安全性(TSL的要求)
客户端获取Access_Token,应该在后台与服务端交互获取Access_Token,不允许Access_Token传给前端直接使用
需要保证Access_Token信息的不可猜测性,以防止被猜测得到
风险5:令牌有效性漏洞
维持refresh_token和第三方应用的绑定,刷新失效机制的设计不允许长期有效的token存在;
四、增强OAuth2.0协议设计及使用规范
OAuth2.0协议安全性进行进一步增强。
-
对颁发出去的token权限进行限制,不同用户申请的token根据人员所属组织、角色、岗位进行数据隔离 -
对登录过程安全性增强,对登录验证方式进行丰富,支持静态密码、手机验证码、OTP、生物识别、FIDO -
对Token颁发后的生命周期管理,可以按策略主动注销颁发的Token -
对使用OAuth过程进行行为分析,对登录过程进行风险识别 -
按照不同应用的安全等级进行分级,不同安全级别应用实现二次认证,保障关键系统的安全访问
以上是关于学习充电OAuth2.0安全设计之Authorization Code的主要内容,如果未能解决你的问题,请参考以下文章