Windows Live ID(WLID)本身是一个identity provider,他负责维护用户的用户名,密码。
作为一个想使用WLID的网站,需要首先注册成为Windows Live application。注册的时候,你先需要有一个WLID! 注册的目标是双方需要有一个PSK——preshared key(WLID叫Secret Key)。这个key是用来验证WLID传回来的token的。注册的同时要求给WLID提供一个Return URL,当用户登录成功,或者logout的时候,WLID会调用这个页面,并且加上一些parameter,其中一个重要的就是stoken,这个参数含有一个WLID传回来的用户相关信息。
我也注册了一个,
return URL=http://sma01:8080/wlid/return.jsp
secret key=thisisaverylongkey
Application ID=<span>00163FFF8000412B</span>
WLID认证成功之后,他就redirect用户到Return URL,相当于SAML的ACS service。另外还要加上token之类的参数。 WLID给用户浏览器返回一个post form,内容如下
<html>
<head>
<noscript>
JavaScript required to sign in
<meta http-equiv="Refresh" content="0; URL=https://login.live.com/jsDisabled.srf?lc=1033″/>
</noscript>
<title>Continue</title>
<script type="text/javascript">
function OnBack(){}
function DoSubmit(){var subt=false;if(!subt){subt=true;document.fmHF.submit();}}
</script>
</head>
<body onload="javascript:DoSubmit();">
<form name="fmHF" id="fmHF" action="<a href="http://sma01:8080/webauth/sample/webauth-handler.jsp">http://sma01:8080/webauth/sample/webauth-handler.jsp</a>" method="post" target="_top">
<input type="hidden" name="stoken" id="stoken" value="DvJ%2BtIPK9bn%2FKlG7PjSB7FNPFEzlX5g9HtHcBGGv2r2h5s1VsnzoRlI7GnSRNK%2Bo3pn87YJCJnTi1jtKgXEh3TLxASGCSt3Okju7MK51VDXz4KGSemv%2BARYN4WJ33FIoHoZ3aVvF19wsNq2YRnM8npmfgVh5ZDVtu%2FXA9FaUqKLRAsOR377dMpDXEWSOrsRQBsmRUy7dZPdZSW4F9%2F%2Fyow%3D%3D">
<input type="hidden" name="action" id="action" value="login">
</form>
</body>
</html>
再看看那个token的具体内容。token首先是base64编码的byte array。前16个字节是IV,剩下来的是加密的内容。加密是用的AES,准确的说,AES/CBC/PKCS5Padding。解密之后的东西居然可以直接得到一个string,看来是iso-8859-1字符集的。顺便说一下,那个decryption key是PSK加上一个前缀"ENCRYPTION",然后做SHA-256,获得的。没有使用PBE的PBRDF2算法,呵呵,让我平衡的很多。我自己做的也只是用SHA-1 hash两次,不过SHA-256可以一次获得16byte的key,的确很省事。
这个解密了的string的最后是一个sig的参数。显然的,这是signature,跟SAML的redirect很类似。不过SAML使用的PKI签名,WLID使用的是HMAC-SHA256 + AES。这里AES的key跟上面的不一样,是用"SIGNATURE"这个前缀+PSK,然后SHA-256获得的。
签名验证成功后,那么这个token就被trust了。里面含有这样几个参数:
appid: application id,这个id应该等于注册windows live application时候产生的一个id,也应该等于local application的id。
ts: timestamp,秒级别的一个时间戳。
uid: user id,我得到的是一个**3661402d031c2a9a6e84505f34d934f0,**看来是因为我没有跟windows live id patner.
flags: 一个int的标记位。程序中写的就是如果是奇数,就使用persistent cookie之类的……不是很紧要。
总之,这里WLID最终给我们提供的比较有意义的就是一个uid。这样用户就可以做sso了。WLID似乎也不给我们提供用户的姓名以及其他的信息,所以,我们只能再做一个数据库,来map用户的信息。有点讨厌,不过可能是处于privacy的考虑吧。
A simple security analysis 在我看来,似乎这里面还是有些安全问题的。其实kerberos协议早就讨论过这些问题了,为什么不做在里面呢?比如,token里面有timestamp,但是本地application如果不检查,显然很容易可以做replay attack,而且可以是很久以后的。即使检查了,也没用,token里面不含有nonce,不含有IP address,如果恶意用户可以sniffer到网络的内容,那么截获了用户浏览器发送到应用的token,也是可以立刻replay,就获得了用户的权限。即使,加了nonce,不能replay,hacker也可以shutdown用户的这个请求,给他发RST,然后大摇大摆的用用户的token去访问服务器,就ok了。这点来说,SAML也有类似的问题,所以,解决方案只能是,所有的过程必须是SSL的。查了一下SAML的文档,它是这么说的:Confidentiality MUST be provided whenever a response is communicated between a site and the user’s browser. This provides protection against an eavesdropper obtaining a real user’s SAML response and assertions. [Section 6.4.1, saml sec consideration] 呵呵,有点较真了,显然地,如果是一个mission critical的application,比如网上银行系统,所有的通讯必须SSL,否则即使认证用SSL,后面的不用,那么cookie也很可能被劫持。