OAuth那些事儿

英国诗人蒲柏在牛顿的墓志铭中写道:『自然和自然的法则在黑暗中隐藏,上帝说,让牛顿去吧,于是一切都被照亮!』,而在保护账号安全方面,OAuth起着如同牛顿般中流砥柱的作用,为什么这么说呢?

人人网提供了导入MSN联系人的功能,但前提是用户必须提供账号密码,如下图所示:

查找你的MSN联系人中有谁在人人网上

查找你的MSN联系人中有谁在人人网上

人人网信誓旦旦的宣称不会记录你的密码,它甚至提供了一个所谓保证账号安全的方法:先改密码再导入,成功后再改为原密码。不过这样做就安全了么?

什么是OAuth

如今很多网站的功能都强调彼此间的交互,因此我们需要一种简单,标准的解决方案来安全的完成应用的授权,于是,OAuth应运而生,看看官网对其的定义:

An open protocol to allow secure API authorization  in a simple and standard method from desktop and web applications.

一个典型的OAuth应用通常包括三种角色,分别是:

  • Consumer:消费方
  • Service Provider:服务提供者
  • User:用户

用户好理解,不必多言,消费方和服务提供者则需要解释一下,举例来说:假设我们做了一个SNS,它有一个功能,可以让会员把他们在Google上的联系人导入到SNS上,那么此时的消费方就是SNS,而服务提供者则是Google。

注:Google APIs支持OAuth

消费方如果想使用服务提供者的OAuth功能,通常需要先申请两样东西:

  • Consumer Key
  • Consumer Secret

当消费方生成签名的时候,会用到它们。

一个典型的OAuth流程通常如下图所示:

OAuth流程图

OAuth流程图

  • A:消费方请求Request Token
  • B:服务提供者授权Request Token
  • C:消费方定向用户到服务提供者
  • D:获得用户授权后,服务提供者定向用户到消费方
  • E:消费方请求Access Token
  • F:服务提供者授权Access Token
  • G:消费方访问受保护的资源

基本就是用Request Token换取Access Token的过程。这里需要注意的是,对服务提供者而言,Request Token和Access Token的生命周期不一样,通常,Request Token的生命周期很短,一般在一个小时以内,这样相对安全一些;而Access Token的生命周期很长,往往是无限,如此一来,消费方就可以把它保存起来,以后的操作就无需用户再授权了,即便用户修改账号密码,也不会受影响,当然,用户可以废除消费方的授权。

有腿的OAuth

我们前面描述的OAuth,被称为三条腿的OAuth(3-Legged OAuth),这也是OAuth的标准版本。这里所谓的“三条腿”,指的是授权过程中涉及三步流程。不过有些情况下,不需要用户的参与,此时就产生了一个变体,被称作两条腿的OAuth(2-Legged OAuth),两条腿的OAuth和三条腿的OAuth相比,因为没有用户的参与,所以在流程中就不会涉及用户授权的环节,而主要是通过Consumer Key和Consumer Secret来完成签名的,此时的Consumer Key和Consumer Secret基本等价于账号和密码的作用。

补充:关于腿的解释详见The OAuth Bible

OAuth简史

2007年12月4日发布了OAuth Core 1.0

此版本的协议存在严重的安全漏洞:OAuth Security Advisory: 2009.1,更详细的介绍可以参考:Explaining the OAuth Session Fixation Attack

2009年6月24日发布了OAuth Core 1.0 Revision A

此版本的协议修复了前一版本的安全漏洞,并成为RFC5849,我们现在使用的OAuth版本多半都是以此版本为基础。

OAuth的未来:OAuth 2.0 Working Draft,…

OAuth和OpenID的区别

OAuth关注的是authorization;而OpenID侧重的是authentication。从表面上看,这两个英文单词很容易混淆,但实际上,它们的含义有本质的区别:

  • authorization: n. 授权,认可;批准,委任
  • authentication: n. 证明;鉴定;证实

OAuth关注的是授权,即:“用户能做什么”;而OpenID关注的是证明,即:“用户是谁”。

如果混淆了OAuth和OpenID的含义,后果很严重。以国内某网站开发的应用为例:它的功能是通过OAuth授权让新浪微博和豆瓣的用户使用各自的身份发表评论,如下图所示:

错误的把OAuth当做OpenID使用

错误的把OAuth当做OpenID使用

此类应用属于身份证明问题,本应该通过OpenID来实现,但因为错误的使用了OAuth,从而带来安全隐患:设想一下用户只是在网站上发表了评论而已,但却赋予了网站随意操作自己私有数据的权利!这就好比:快递员送包裹,为了证明收件人的身份,原本你只要给他看一下身份证即可,可你却把防盗门钥匙都给他了!Oh,My God!

收工!作为首尾呼应的结束语,请允许我套用蒲柏的话:『账号和账号的安全在黑暗中隐藏,上帝说:让OAuth去吧,于是一切都被照亮!』,不过这可不是墓志铭 🙂 。

补充:关于OAuth详细的介绍可以参考Beginner’s Guide to OAuth

OAuth那些事儿》上有61条评论

  1. Pingback引用通告: 火丁:OAuth那些事儿;冉云飞:教育父母 | 海尋資訊

    • 记住文中所举快递员例子中“防盗门钥匙”和“身份证”的意义,可以很容易的区分OAuth和OpenID。

  2. Pingback引用通告: Tweets that mention OAuth那些事儿 | 火丁笔记 -- Topsy.com

  3. 近期要搭建一个Oauth的Server端,oauth的校验流程已经搞明白了。
    可是不是很明白oauth中签名(signature)的意义是什么。我为什么不简单的使用key和secret(有需要的話就加上timestamp和nonce)。

    对于oauth,我简单的理解就是:把user和consumer关联起来。不知道这样理解是否过于肤浅?

    • 签名的意义在于防止请求被篡改。如果没有签名,只是简单的使用Consumer Key和Consumer Secret,那和HTTP Basic还有什么区别?!实际使用OAuth的时候,请求中是不包含Consumer Secret的,它只是参与签名的计算,所以,就算请求被别有用心的人截获也是没用的,因为他不知道Consumer Secret,所以算不出正确的签名,也就无法构造出合法的请求。

      3-Legged OAuth就是通过User的授权,Consumer可以访问User在Service Provider的数据;至于2-Legged OAuth,没有User的参与,只是Consumer和Service Provider的交互。

  4. Pingback引用通告: OAuth那些事儿 | 网摘

  5. 一语道破,刚刚认真整理了一下思路,终于从死胡同里转出来了=.=
    通过Oauth访问需要认证的API的时候,一般需要如下参数。
    oauth_consumer_key
    oauth_token Access Token
    oauth_signature_method
    oauth_signature
    oauth_timestamp
    oauth_nonce
    所以就算有人把以上所有信息截获了,但没有consumer_secret,是無法計算出正確的signature。

    终于理解签名的意义,多谢耐心解惑:)
    终于不用登录也能在你blog留言了,呵呵

    • 但是不是已经直接获取到signature了吗,因为signature就在参数中

  6. 搭建oauth server的时候,遇到一个问题:

    “consumer请求request token”“用户授权request token”这个过程,并不是一个持续的过程(需要用户介入操作)。请求到授权的这段时间,作为oauth server(假设用php实现),应该如何存储这个“未授权”的request token比较合适呢?

    因为consumer可以通过socket等方式向server发出模拟请求,所以在server端无法使用session存储。

    我之前是使用数据库存储,当consumer请求request token的时候,server将生成request token相关信息存入数据库。数据库中的表有一个字段标识此request token是否被授权。等到用户确认授权给request token之后,更新该标识字段。

    问题在于,如果用户迟迟不授权,那么这条数据就一直存在于数据库中。

    我有想过写一个定时任务,定时删除表中过期的request token。又或者使用memcache来存储这个“未授权”的request token,但这样好像又有点大材小用。

    存储这个“临时的”未授权的request token,应该怎么设计才合适?

    • 本文主要是从用户的角度来讲解OAuth,服务端不是本文主题,建议你参考oauth-php,它包括了服务端的实现方式。

  7. 关于你举的水煮鱼那个例子,我觉得有失偏颇。单纯从技术角度的确如你所说是用错了,但现实是服务提供方并未提供OpenID服务,而是用OAuth来包揽了——所以这个错不在使用者而在于提供方

    • 讲个笑话:快递员送包裹,因为我找不到身份证证明自己的身份,快递员就想把我的防盗门钥匙拿走,还说这个错不在他而在我。

    • 其实我觉得这个还用送快递来比喻:快递员公司规定,必须用防盗门钥匙验证你的身份,而根本不会看你的身份证是否合法,所以,作为用户,为了得到这个包裹,要么冒着家里被盗的危险,用钥匙签收,要么只能拒收。(突然看到下边还有“注册为本站会员”,那么再加一条,如果非要签收的话,要么给钥匙,要么用身份证注册为快递公司的VIP)

    • 我觉得Oauth还有一个好处是实现部分权限,比如这个用豆瓣帐号登录的例子,之后肯定会跳到豆瓣的网站要求登录,然后问你开放那些权限给这个应用,如果有一个选项是“仅开放必要信息证明我是豆瓣用户”那么也可以实现openid的效果。。。用快递来比喻似乎有失偏颇,因为有数据的网站server,这里是豆瓣,只要能向这个应用证明这个用户确实是豆瓣用户就可以了,其他的权限可以不开放给它。。。。等下,要实现如上用豆瓣帐号登录的功能好像必须在豆瓣那边注册一个应用才行,嗯,就是这样。

发表评论

电子邮件地址不会被公开。 必填项已用*标注