oAuth无痛入门指南
决心写个入门指南,理清思路。当然,如果你真的要仔细研究下oAuth,请看官方文档 http://oauth.net/core/1.0/ 。这里的东西最权威。也可以去oAuth邮件列表 讨论。
一句话oAuth
oAuth涉及到3大块的交互和通信。1. 用户 ,2. 拥有用户资料/资源的服务器A ,3. 求资源的服务器B ,。
oAuth的典型应用场景(senario)
以前,用户 在 拥有资源 的的网站A有一大堆东西;现在用户发现了一个新的网站B,比较好玩,但是这个新的网站B想调用 拥有资源的网站A的数据。
例如,
- 在线打印服务的网站,需要调用我的私人Flickr图片。
- xiaonei.com之类的SNS在线社交网站需要从我的Hotmail导入联系人
那么有以下几个方法:
- 需要转移的数据如果是一段文字的话,用户自己Ctrl+C, Ctrl+V。如果是图片呢?复制就麻烦了。
- 用户自己下载再上传。——麻烦
- 用户老老实实把自己账户ID和密码交上来,服务器自动去抓取。——这个等于把自己家的钥匙给别人来让别人借书一样。。。
oAuth的方式
用户在 求资源的网站B 上,点击一个URL,跳转到 拥有 资源的网站A。
拥有资源的网站A提示:你需要把资源分享给B网站吗?Yes/No。
用户点击 Yes ,拥有资源的网站A 给 求资源的网站B 临时/永久 开一个通道,然后 求资源的网站 就可以来 拥有资源的网站 抓取所需的信息了。
那么具体的说就有3个步骤:
- 首先是2个服务器之间的。求资源的网站B向拥有资源的网站A发送一个请求。术语叫Obtaining an Unauthorized Request Token 。具体的作用,类似写了一个“资源远程调用申请书” 给 拥有资源的A网站
- 第二步是,用户在拥有资源的网站A 通过/允许这个请求。术语叫Obtaining User Authorization 。类比一下,就是用户给这个申请书盖章 通过啦。
- 最后一步仍然是服务器之间的通信。回到B网站,求资源的网站B临时/永久拥有了在A网站远程调用资源的权限,术语又叫Obtaining an Access Token 。就好比得到了一个“黄金招牌(Access Token)” 。只要每次带上这个“黄金招牌”,求资源的网站B 就可以大摇大摆去 拥有资源的网站A 抓取任意有权限可以被抓取的资源了。具体的技术细节,就是拥有资源的服务器A返回了类似这样的一个
application/x-www-form-urlencoded
字符串:oauth_token_secret=ssssssssss&oauth_token=ttttttttttttttt&other_parameters =1331775
, 这个时候,oauth_token 就相当于用户的密码,你可以用这个oauth_token做任意权限之内的事情了。oauth_token_secret是私钥。 other_parameters是服务器返回的其它可选参数。一般来说,你可以把这个oauth_token的值保存起来,下次接着用。而且一般来说一 个用户和一个oauth_token是一一对应 的。
传递oAuth参数
Technically。当然2个服务器之间传输数据的时候,这里面有一些秘密的oAuth参数以保障整套体系是安全可靠的。这些参数叫Consumer Request Parameters(在oAuth 1.0规范5.2里 定义的)。具体的来说,传递oAuth参数有3种方法:
- 通过HTTP GET,在URL里面,? 后面的一堆参数。个人不推荐这种方法,因为用一个iframe或者img就可以被XSS了。
- HTTP POST方法,参数Content-Type格式为
application/x-www-form-urlencoded
- 通过
Authorization
这个HTTP头。传递的东西有一定的格式要求,叫OAuth HTTP Authorization Scheme
这套体系有个比较龌龊的特性,对开发人员十分麻烦,但是对保密性做得比较好,叫“签名”。而且这个特性不是可选的,是必须的。
签名
什么是 签名(Signature)
数字签名不是指将你的签名扫描成数字图像,或者用触摸板获取的签名,更不是你的落款。
数字签名在防止篡改,防止重放攻击,保证数据完整性,防止假冒签名,防止签名者抵赖方面更有效。在中国大陆,数字签名 是具法律效力的。
目的:在保证安全(不泄漏密码,防止中间人攻击 )的前提下,尽量简单的设计一套可靠“授权”体系。
oAuth官方定义 了3种方式,分别是HMAC-SHA1 , RSA-SHA1 和PLAINTEXT 。当然各个支持oAuth的服务器也可以自定定义一套体系。但是签名的大概过程都差不多。
需要签名的数据依次是:
- HTTP方法是GET, POST还是HEAD?
- 规范化表示 的HTTP URL
- 编码合并过后的oAuth参数列表
这3部分需要用 & 符号连接起来,然后交给hmac或者RSA加密。当然我讨厌这么麻烦的方式,所以我用最后一种,也是最简单,各个oAuth服务基本都支持的“签名” 方式:PLAINTEXT 。
具体的很简单,每次请求的时候,oAuth参数包括一个oauth_signature
就行了。值就是拥有资源服务器提供的secret key
再次讨论oAuth参数:术语解释
oauth_consumer_key
求资源的网站B的一个标识符。可以认为世界上有许许多多类似 网站B 这样的需求。每一个服务都给了一个唯一的标识符。这个东西哪里来的?自己去问 拥有资源的网站A。例如douban就提供了一个Douban API Key ,这里就填Douban API Key好啦。oauth_consumer_secret
上面那个东西的私钥。如果是Douban,就填API Key的私钥。oauth_token
oAuth进行到最后一步得到的一个“黄金招牌”。有了这个“黄金招牌”,求资源的网站B 就可以大摇大摆去 拥有资源的网站A 抓取任意有权限可以被抓取的资源了。oauth_token_secret
上面那个东西的私钥oauth_signature_method
签名方法。三选一:SHA1, RSA-SHA1或者PLAINTEXT。哦。不对。不是三选一,oAuth服务商可以自定义的。oauth_signature
签名值。这个得靠你自己把数据揉到一个加密函数里算出来。具体如何算看这里 oauth_timestamp
时间戳。timestamp。不懂的自己google。oauth_nonce
这个就是一个临时值,只要保证每次请求,这个值都不一样就行了。一般随机生成一截数字。
实践
说了这么一大堆东西,还是应该弄一个library 来完成这一系列工作。哈哈。不要重复发明轮子 嘛。例如oauth-python
。我个人觉得很可惜的是,如果你有把这个库弄懂,会用那个精力,还不如自己实现一个库算了。汗。
oAuth的其他
oAuth在安全领域里,是一套相当有Web特征的“授权(authorization) ”体系。
oAuth 有个好处,就是认证不一定是基于Web的,假如你写了个桌面程序,或者说widget,或者说javascript webapps,也可以直接采用oAuth。其实est个人在想的话,如果采用各个浏览器的cookiejar文件解析 + Flash的LSO ,加上oAuth,基本可以做到一次登录永久授权了。
oAuth的诞生可以说是豪门云集啊。一出来的目标就是统一各个网络服务商的各自的登录/授权/认证API,例如Digg, Jaiku, Flickr, Ma.gnolia, Plaxo, Pownce, Twitter, Google, Yahoo, and others soon to follow。不服气的可以再去看看oAuth 1.0规范的作者列表 ,那些email地址都是牛B闪闪的大公司大巨头牛人啊。
国内的话,Douban采用的是oAuth,虽然用起来有点麻烦,但是支持oAuth应该算一个非常国际化标准化的举措了。
问题在哪里?
假如有一个网站,既扮演了求资源的服务器A 这个角色,又扮演了用户 角色。加上X技术Y方法Z漏洞。。。。。