不知道为什么,关于 X-WSSE 验证的中文资料很少,英文资料也不是很多,能搜到的资料年代都非常久远,最早可追溯到 2003 年1,可能这种验证方式太古老而且存在什么弊端,所以在随后的很多年里人们发现、发明了其他更常用的验证方式?
关于 HTTP 的各种验证方式我其实一种都不知道…X-WSSE 这一种奇怪的方式是我在整合 Emarsys 的 API 时了解到的。由于自身比较懒,就到 Github 上搜搜有没有现成的能够生成 UsernameToken 的包可以用,以省去重复发明轮子的功夫,然而掉进了坑里,与node-wsse的作者大战了好几个回合…
此文章不讨论验证的原理,只讨论 X-WSSE UsernameToken 的生成方式,其中主要是生成passwordDigest。 验证嘛,用户名 username,密码 password 肯定是少不了的,此外还需要 nonce,timeStamp,有了这几样再按照下面的步骤一步步就可以生成符合 WSSE 标准的 token 了。
UsernameToken 的生成一共需要5 个步骤:
- 生成一个随机字符串 nonce。不同公司的 API 对这个 nonce 的要求可能会不同,有一些要求采用
base64
编码方式,比如symfony 给出的例子; - 时间戳(timeStamp)。对于时间戳,统一采用ISO-8601格式的字符串,但是不同公司的 API 对时区(timezone)的要求可能会不同,比如 Emarsys 要求 UTC,Adobe 要求 GMT;
- 把 nonce,timeStamp,password 这三个字符串按顺序连接起来形成一个新的字符串,并将这个字符串按照SHA1方法加密。 坑来啦,坑来啦,坑来啦!!! 一个字符串通常加密之后密码摘要默认是 binary 的,比如 Adobe2,但有些公司可能要求以 hex 方式生成摘要…比如万恶的 Emarsys3…而关于这个摘要到底应该是 binary 还是 hex,据说业界也是模糊不清的,只能由着各家公司按自身情况使用两种方式中的某一种来实现验证4;
- 把上一步得到的密码摘要按照
base64
进行编码,就能得到 passwordDigest; - 按照以下方式拼接字符串,把各个双引号内换成上面步骤所提到的值,即可得到 UsernameToken,看起来长这样:
UsernameToken Username="username", PasswordDigest="passwordDigest", Nonce="nonce", Created="timeStamp"
- http://www.xml.com/pub/a/2003/12/17/dive.html↩
- https://marketing.adobe.com/developer/cn/documentation/authentication-1/wsse-authentication-2↩
- http://documentation.emarsys.com/resource/developers/api/getting-started/authentication/↩
- http://book.soundonair.ru/web/web2apps-CHP-11-SECT-1.html#web2apps-CHP-11-SECT-1.8↩