移花接木:针对OAuth2的CSRF攻击

作为第三方应用,为了提升用户体验,往往会提供第三方社交账号登录或者绑定的功能,这背后使用到的关键技术是OAuth认证。想要在自己的应用里集成OAuth不是难事儿,各大社交网站都提供了详尽的文档指南。

OAuth的复杂度比较高,有不少安全方面的坑,开发者在使用过程中一不注意可能就会掉进去,比如说不正确的使用OAuth2可能会遭遇到CSRF攻击。本文将对这个安全风险做一个通熟易懂的解释。

老司机发车前的特别提醒:阅读本文可能需要你对OAuth2有一些了解,可以参考文末的链接进一步了解OAuth2。


1. OAuth2 授权模式回顾

在开始之前,让我们先来回顾一下OAuth2中最典型的Authorization Code 授权模式,其大致流程如下:

图1:OAuth2 Authorization Code Flow

我们把OAuth2的整个认证过程大致分为三个阶段。第一阶段主要是向用户取得授权许可,对应图中的第1、2、3步;第二阶段主要是申请访问令牌(access_token),对应图中的第4、5步;第三阶段就是使用access_token获取用户数据。

这一过程中涉及了不少的敏感参数和数据,例如client_secret相当于是第三方应用自己的密码,access_token某种程度上来讲就是用户的session id。由于这些参数以及数据及其特殊,我们当然得确保它们的安全性,HTTPS加密传输以及安全存储是必不可少的防护手段。不过仅仅做到这些是远远不够的,在这个流程里存在一个弱点,容易被攻击者利用进行CSRF攻击。

2. 针对OAuth2的CSRF攻击

2.1 攻击流程

让我们来看一个针对OAuth2的CSRF攻击的例子。假设有用户张三,攻击者李四,第三方Web应用Tonr(它集成了第三方社交账号登录,并且允许用户将社交账号和Tonr中的账号进行绑定),以及OAuth2服务提供者Sparklr。

图2:模拟攻击案例中涉及的角色

Step 1. 攻击者李四登录Tonr网站,并且选择绑定自己的Sparklr账号
Step 2. Tonr网站将李四重定向到Sparklr,由于他之前已经登录过Sparklr,所以Sparklr直接向他显示是否授权Tonr访问的页面
Step 3. 李四在点击”同意授权“之后,截获Sparklr服务器返回的含有Authorization code参数的HTTP响应
Step 4. 李四精心构造一个Web页面,它会触发Tonr网站向Sparklr发起令牌申请的请求,而这个请求中的Authorization Code参数正是上一步截获到的code
Step 5. 李四将这个Web页面放到互联网上,等待或者诱骗受害者张三来访问
Step 6. 张三之前登录了Tonr网站,只是没有把自己的账号和其他社交账号绑定起来。在张三访问了李四准备的这个Web页面,令牌申请流程在张三的浏览器里被顺利触发,Tonr网站从Sparklr那里获取到access_token,但是这个token以及通过它进一步获取到的用户信息却都是攻击者李四的。
Step 7. Tonr网站将李四的Sparklr账号同张三的Tonr账号关联绑定起来,从此以后,李四就可以用自己的Sparklr账号通过OAuth登录到张三在Tonr网站中的账号,堂而皇之的冒充张三的身份执行各种操作。

等等,这一切发生得太快,还没看清楚李四怎么就登录到张三的账号里去了。没关系,让我们从几个不同的角度来看看这当中发生了什么。

2.2 受害者张三(Resource Owner)视角

受害者张三访问了一个Web页面,然后,就没有然后了,他在Tonr网站上的账号就和攻击者李四在Sparklr上的账号绑定到了一起。伪造的请求是经过精心构造的,令牌申请这一过程在张三的浏览器里是非常隐蔽的被触发的,换句话讲就是,他根本不知道这背后发生了什么。

2.3 Tonr网站(Client)视角

从Tonr网站来看,它收到的所有请求看上去都是正常的。首先它收到了一个HTTP请求,其代表着当前用户张三在Sparklr网站上已经做了“同意授权”操作。其内容如下:

GET /bindingCallback?code=AUTHORIZATION_CODE

不过需要注意的是,URL里的code不是当前受害者张三的Authorization Code,而是攻击者李四的。

当Tonr收到这样的请求时,它以为张三已经同意授权(但实际上这个请求是李四伪造的),于是就发起后续的令牌申请请求,用收到的Authorization Code向Sparklr换取access_token,只不过最后拿到的是攻击者李四的 access_token

最后,Tonr网站把攻击者李四的access_token和当前受害者张三在Tonr网站上的账号进行关联绑定。

2.4 Sparklr网站(OAuth2服务提供者)视角

Sparklr网站也是一脸茫然的样子,因为在它看来,自己收到的授权请求,以及后续的令牌申请请求都是正常的,或者说它无法得知接收到的这些请求之间的关联关系,而且也无法区别出这些请求到底是来自张三本人,还是由李四伪造出来的。因此只要自己收到的参数是正确有效的,那就提供正常的认证服务,仅此而已。

2.5 攻击者李四视角

李四伪造了一个用户授权成功的请求,并且将其中的Authorization Code参数替换成了自己提前获取到的code。这样,当受害者的浏览器被欺骗从而发起令牌申请请求时,实际上是在用张三在Tonr网站上的账号和李四在Sparklr网站上的账号做绑定。

攻击完成后,李四在Tonr网站上可以通过自己在Sparklr网站的账号进行登录,而且登录进入的是张三在Tonr网站上的账号。而张三通过自己在Tonr网站上的账号登录进去之后,看到的是李四在Sparklr网站上的数据。

2.6 上帝视角

从整体上来看,这次攻击的时序图应该是下面这个样子的:

图3:攻击时序图示

3. 漏洞的本质

这个问题的关键点在于,OAuth2的认证流程是分为好几步来完成的,在图1中的第4步,第三方应用在收到一个GET请求时,除了能知道当前用户的cookie,以及URL中的Authorization Code之外,难以分辨出这个请求到底是用户本人的意愿,还是攻击者利用用户的身份伪造出来的请求。

于是乎,攻击者就能使用移花接木的手段,提前准备一个含有自己的Authorization Code的请求,并让受害者的浏览器来接着完成后续的令牌申请流程。

4. 前提条件

尽管这个攻击既巧妙又隐蔽,但是要成功进行这样的CSRF攻击也是需要满足一定前提条件的。

首先,在攻击过程中,受害者张三在Tonr网站上的用户会话(User Session)必须是有效的,也就是说,张三在受到攻击前已经登录了Tonr网站。

其次,整个攻击必须在短时间内完成,因为OAuth2提供者颁发的Authorization Code有效期很短,OAuth2官方推荐的时间是不大于10分钟,而一旦Authorization Code过期那么后续的攻击也就不能进行下去了。

最后,一个Authorization Code只能被使用一次,如果OAuth2提供者收到重复的Authorization Code,它会拒绝当前的令牌申请请求。不止如此,根据OAuth2官方推荐,它还可以把和这个已经使用过的Authorization Code相关联的access_token全部撤销掉,进一步降低安全风险。

5. 防御办法

要防止这样的攻击其实很容易,作为第三方应用的开发者,只需在OAuth认证过程中加入state参数,并验证它的参数值即可。具体细节如下:

  • 在将用户重定向到OAuth2的Authorization Endpoint去的时候,为用户生成一个随机的字符串,并作为state参数加入到URL中。
  • 在收到OAuth2服务提供者返回的Authorization Code请求的时候,验证接收到的state参数值。如果是正确合法的请求,那么此时接受到的参数值应该和上一步提到的为该用户生成的state参数值完全一致,否则就是异常请求。
  • state参数值需要具备下面几个特性:
    • 不可预测性:足够的随机,使得攻击者难以猜到正确的参数值
    • 关联性:state参数值和当前用户会话(user session)是相互关联的
    • 唯一性:每个用户,甚至每次请求生成的state参数值都是唯一的
    • 时效性:state参数一旦被使用则立即失效

6. 总结

state参数在OAuth2认证过程中不是必选参数,因此第三方应用开发者在集成OAuth2认证的时候很容易会忽略它的存在,导致应用易受CSRF攻击。此外,这样的攻击非常巧妙,可以悄无声息的攻陷受害者的账号,难以被察觉到。

不过作为第三方应用的开发者,我们只需要在OAuth认证流程中明确提供state参数并验证其参数值,即可轻松防御这样的攻击。

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容