2010年5月30日星期日

A for Authentication

每当看见 MSN 上失散多年的好友发来壮阳药广告或皮条俱乐部邀请信,我就轻轻将此信归入垃圾邮件,然后叹息又一个倒霉蛋中招了。中招源于轻信 —— 把自己的用户名和密码告诉了第三方,如非官方的网页版聊天器,或 SNS 网站上寻找 MSN 好友在本网站马甲的工具。密码本是用户和服务商两者之间你知我知的事,但用户找人代办某事时把密码给了这个不相干的第三者,后果是身份被人冒用。这还不是最糟的,冠希兄现在也该明白两人的事如果让第三人知道了,全世界就都知道了。

不同的人,与之共享的秘密也不一样:商业机密不该告诉家人;家里的糗事不该带到职场;兄弟的往事打死灌醉也不能透露给他现任婆娘。网络上也一样,别说银行帐号密码不能泄露给第三方(哪怕他自称公安局),公司网络的登录帐号、个人 MSN 和 GMAIL 邮箱也不能外泄。就连网络游戏也反复告诫脑残玩家 —— 问你账户密码的人绝不是本公司客服。随着各类网络服务不断增多,需要记住的账户越来越多,脑子越来越不够用。应该有解决之道,让我把线索理一理。以下是我的学习笔记,为了今后的自己还能看懂,尽量科普省略细节。


Authentication: 识别认证(向我证明你是谁)
Authorization: 授权许可(我知道你是谁,现在决定允许你干啥)
Accounting: 审计监察(检查你究竟干了啥)

前两者很容易混淆。两周前我回顾信任的传递体系,证书这东西其实是把前两个 A (认证+授权)串起来了。现实世界里,授权的传递(Delegate)很复杂,三个月前在讨论 UAC 时我就感觉头大,所以今天干脆放弃授权部分。只谈第一个 A,识别认证,这是用户参与度最大的一步。要完成身份验证,除了不太常用的指纹、智能卡、密保卡之类的外设,最常见的就是在键盘上敲用户名密码。


Single sign-on —— 公司里常用的认证技术,比如 Kerberos 协议的 Windows 集成认证。大致原理就是所有资源和服务都信任一个中央认证系统,用户只要向这个中央认证系统证明自己的身份,别的资源和服务就无条件相信用户的身份。至于用户在各资源或服务上的权限,可以中央控制也可以下放到地方。

在一个封闭的环境里,比如一家公司,设立一个权威的中央认证机构当然没问题。但同样的模式放到开放的社会里能行得通么?几乎所有网站都有自己的帐号 验证系统。不管做啥生意客户资料都是命脉,这信息托管出去就好像被人捏住了蛋蛋,人家时不时捏你一下,随时能让你完蛋。

另 一方面用户也不希望把自己的所有帐号都关联起来,这样做就等于实名制,既不自由也没了安全。网民的安全感是建立在隐私保密的基础上的,保护隐私靠的是商业 伦理而非政府行为。个人资料越分散就越安全。试想一个机构掌握了全社会所有人的所有资料,这机构除了上帝就一定是 KGBStasi, 太可怕了。英 国政府宣布百日内废除身份证,Google 近来关于隐私保护的官司缠身,很大程度也是因为民众的这种心理。




好吧,那把选择权留给用户,他们爱在哪里认证就在哪里认证,当他们需要用此处的身份去别处登录时,也可以,只要各服务商都遵守门户开放公约。这就好像拿着护照出国一样。OpenID 标准由此而来。早在它诞生以前,微软就抢注了 passport.net 域名用于用户身份的验证,这名字真太形象了。下面是一些遵守这个公约的网站:

Site URL Format Comments
Google https://www.google.com/accounts/o8/id Google does not require the username to be passed in the openID string.
Yahoo! openid.yahoo.com Yahoo! began allowing their usernames to be used as openIDs beginning January 31, 2008. Yahoo! does not require the username be passed in the openID string.
Microsoft accountservices.passport.net/ Windows Live ID
Facebook facebook.com/username/ Facebook
LiveJournal username.livejournal.com LiveJournal supports OpenID as both a provider and a relying party.
MySpace myspace.com/username
WordPress username.wordpress.com
Blogger username.blogger.com
Verisign username.pip.verisignlabs.com Verisign offers a secure OpenID service, with two-factor authentication, which they call "Personal Identity Provider"
Typepad blogname.typepad.com
MyOpenID username.myopenid.com
Google Profile google.com/profiles/username
Orange openid.orange.fr/username or just orange.fr/ Offers OpenIDs to their 40 million broadband subscribers, and accepts OpenID to allow non subscriber users to access a subset of services.
Launchpad launchpad.net/~username See https://help.launchpad.net/YourAccount/OpenID for details.

五年以来,情况似乎没啥变化。至少我登录 MSN 和 Google 都用它们各自的帐号。就像一个人有多重国籍,到哪个国家就使用当地护照,避免受歧视。毕竟本国公民的权限大一点,有些服务可能不对外来人开放。一个国家对非本国颁发的护照,信任度方面也会打折扣。还有 OpenID 容易受钓鱼攻击也是它不受待见的原因之一。总之,英特纳雄耐尔就一定要实现。哪一天?没准。实现了一切会更好么?难说。也许没人在乎。


听说 Microsoft, Google, Yahoo 和 MySpace 都开始支持一个叫 XAuth 的服务,就去学习了一下。试用完这个 Demo,看了看 Google 的说明Meebo 的科普,才明白它和我理解的 Authentication 根本不沾边。

这东西其实是方便网页的设计者从一个统一的地方(XAuth.org)获取当前用户浏览器同时登陆的其它社交网站的列表。近期因隐私保护官司缠身的 Google 还特意澄清:我们给 XAuth 的只是当前浏览器是否有帐号登录我们的服务,至于是哪个帐号(假设你有多个 Google 帐号)我们是不会告诉它的。也就是说,没有真正的传递 Authentication 信息。这纯粹是锦上添花脱裤子放屁:去访问某个网页,上面可能会有个 Google 的图标,如果你这时正好登录了 Google 这图标就亮着,如果你没有登录它就暗着或者隐藏 —— 注意这只是你自己状态,XAuth 无法提供你好友是否在线的信息因为它只认浏览器不认帐号。鸡肋呀鸡肋,想出这个功能的人很蛋疼吧。


让服务员帮忙泊车却不想他拿了车钥匙就跑了,让人帮忙修理电脑结果硬盘上的照片上网了,把邮箱密码告诉了别人结果该邮箱就开始以你的名义发壮阳药广告了。这些操作中 key 同时承担了身份验证和授权的责任。其实让人帮忙只要授权即可,本来是不必把用来识别身份的 key 交出去的。

年初时我学 Python ,在 GAE 上写了个 Twitter 的应用。用 Basic Authentication,即用户把密码发给我这个应用程序,然后这个应用再把密码转发给 Twitter 完成认证。我的程序自己用,犯不着自己偷自己密码,可别人写的应用就不好说了。六月底 Twitter 就不再支持这种认证方式了,我非常赞成。这年头信息安全越来越重要,账户信息外泄一方面用户身败名裂,另一方面服务商也很难追查 —— 用户自己干的还是第三方干的怎么说得清楚?

OAuth 解决问题的方法就是把认证和授权分开,认证仅由两方完成,牵扯第三方时使用临时令牌。这样做减小了身份被冒用和过度授权的风险。以 Twitter 为例,用户是甲方,Twitter 是乙方,第三方程序是丙方,大致过程如下:


1、第三方写好自己的程序以后,去 Twitter 处注册一下,得到 CONSUMER_KEY 和 CONSUMER_SECRET。(相当于证明自己身份的用户名密码)

2、当用户通过第三方访问 Twitter,第三方先去 Twitter 处用自己的 CONSUMER_KEY 和 CONSUMER_SECRET 登录后得到一个 Request Token。(这是一块临时令牌,可以共享给用户,拿到临时令牌的用户可以以此向 Twitter 证明自己是从那个第三方来的,但却不必知道第三方的密码。)

3、用户拿着这块临时令牌亲自访问 Twitter 输入用户名密码。这样 Twitter 不但确认了用户的身份,而且还知道他是哪个第三方应用介绍来的,它就问用户是否授权这个第三方应用访问他的账户。

4、用户授权后,Twitter 把这个用户返还给第三方应用,交还第一块令牌和一个 oauth_verifer 作为收条。

5、第三方将第一块令牌、收条加上自己的 CONSUMER_KEY 和 CONSUMER_SECRET 再次去 Twitter 认证,得到 Access Token,这是第二块临时令牌。

6、之后第三方应用使用这张 Access Token 临时令牌访问 Twitter 就可以代替用户首发消息了。

至此用户和第三方都在 Twitter 处证明了自己的身份,而彼此又不共享密码。以用户向第三方“授权”的方式取代了从前的“冒名顶替”,即便第三方干出了什么出格的事,Twitter 那边也有案可查。完美地实现了 AAA ,虽有些繁琐,但目前我也想不到更简化的流程。

一枝红杏出墙来

注意 OAuth 第 3 步,用户仍需亲自访问 Twitter 完成验证,对于天朝用户,我们和 Twitter 之间隔着伟大的墙。当初我写 GAE 的 Twitter 应用就是为了给手机凿一条穿墙通道。废除 Basic Authentication 以后如果我的程序严格走完 OAuth 流程,用户每登录一次就要翻墙一次。怎么解决这个问题?用 gtap 和 Malloc 的改版,十分钟搞定。原理就是在上述第 5 步以后,把 Access Token 保存在第三方程序的数据库中,并给用户一个 API 密码。以后每次用户用这个 API 密码调出这第二张令牌,第三方程序就用它访问 Twitter 不必重复 1~5 步了。

Twitter 客户端,手机上我用 ÜberTwitter,听名字像是德国造( Über = Super );Chrome 浏览器里用 Chrowety 巴西造。两者都支持自定义 API 地址,正好配合 Malloc 版本的 gtap 使用。BTW,世界杯快开始了,这俩传统强队都有主力缺席,但我还是支持他们。只可惜我叶公好龙,上届世界杯没一场球看全了的,本届估计也一样。折腾了这么半天 Twitter 其实我只是个潜水员,除非遇到找不着厕所或忘带草纸这类悲剧,Twitter 上我只收不发,就当它是第二个 Google Reader 。这东西好处就是实时,互联网比图书馆的优势就在这里:当年的 911 之夜我第一时间在 ICQ 上听陌生人说的,去年央视大楼着火和新疆维汉冲突我在饭否上看的文字加照片直播。说不定哪天敏感词寿终正寝了,极有可能我最先会在 Twitter 上看到,好赶在鞭炮和啤酒被人们抢购一空之前...

既然说到了翻墙,Chrome 上另一个好用的梯子是 Switchy,装了它以后我用 Firefox 的次数越来越少了。手机上 Opera Mini 要用可以改服务器的那个版本,走德国服务器,因为默认的服务器会驳回你的避难申请把你直接遣返回国,最终你还是落在敏感词的手里。万一哪天德国也和天朝签订难民遣返协议了,就用 GAE 或别的什么境外网站自己动手搭个 Opera Mini 代理,代码简单到几句话,原理就是三级跳。

好啦,就到这里,休息,休息一会儿。

没有评论: