且听疯吟 在此记录扯淡的青春

这个问题之前很好解决,使用浏览器 plugin 即可。
但是随着 Chrome 和 Firefox 都先后放弃了 NPAPI plugin,这一方法也行不通了,而且很多人是很讨厌 plugin 的。
但是在默认禁止了 NPAPI 的 Chrome 版本,QQ 依然可以实现快速登录(一键登录),是怎么做到的呢?

原理

其实不难猜。既然不存在 plugin,无法以此来实现浏览器内和本地客户端的直接通信,那么排除其他的黑科技,有一种很简单的方法可以实现这个效果。
那就是在客户端开一个 Server,在浏览器里面请求这个地址。
理论上这样是可以实现的,至于 QQ 是不是用的这种方法,稍微验证下好了。

验证

  • 找一个有 QQ 快速登陆的页面,比如 mail.qq.com
  • 登陆 QQ 客户端
  • 打开浏览器的 Developer Tools -> Network
  • 刷新页面,观察所有请求的 domain
  • 好明显,这就是我们要找的了
    • 完整请求 url 是这样的
      https://localhost.ptlogin2.qq.com:4301/pt_get_uins?callback=ptui_getuins_CB&r=0.22949112393586502&pt_local_tk=-2027291081
    • 看看这个请求的 Response Content
      var var_sso_uin_list=[{"account":"xxxxxx","client_type":65793,"face_index":0,"gender":1,"nickname":"xxx","uin":"xxx","uin_flag":xxxxx}];ptui_getuins_CB(var_sso_uin_list);
      

      很明显是当前登录的用户信息

    • ping 一下这个请求的 domain
      不出所料结果是 127.0.0.1

      ping localhost.ptlogin2.qq.com
      :: Pinging localhost.ptlogin2.qq.com [127.0.0.1] with 32 bytes of data
      
  • 现在我们验证下是否是 QQ 开了这个 Server
    • 查看哪个程序占用了 4301 端口

      netstat -ano | findstr "4301"
      ::  TCP    127.0.0.1:4301   0.0.0.0:0   LISTENING   14516
      
    • 得到 pid 我们就可以看否是 QQ 在监听这个端口了
      tasklist | findstr "14516"
      :: QQ.exe  14516 Console   2     87,892 K
      

安全

可能有人担心会不会有安全问题,会不会其他网站访问这个 url 就拿走用户信息?其实挺容易解决,存一个 token 到服务端,获取的时候校验下就好了。
但是归根到底取决于腾讯对这方面安全的重视程度和意愿了,至少之前是确实存在从网页上获取当前登录的 QQ 信息的方法,虽然问题不是出在快速登录这部分。

越来越多的网站开始更加关注安全问题了,比如,Facebook 会在你把密码从 abc123 改为 Abc123 的时候的时候提示你

Your new password is too similar to your current password. Please try another password.

很贴心是不是?但是,他们是怎么做到的?难道 Facebook 保存了用户的明文密码么?

编辑距离

计算两个字符串的相似性,或者说「编辑距离」很容易,我们有很多现成的算法和代码。
但是,显然 Facebook 不会傻到存储明文密码,存储的肯定是 hash("abc123")
而字符串中的差别和 hash 结果并不是一一对应的。两个相近的字符串,其 hash 结果可能差别很大。

simhash

可能你听说过 simhash 算法。Google 就是使用这种算法来做网页查重的。
传统的 hash 算法如 md5,一般尽可能要求结果分布均匀,因此,原始字符串的微小变动也会导致 hash 结果出现很大差异。
而 simhash 是一种局部敏感的 hash 算法,选定位数,提取特征,然后对每一段特征值计算 hash,然后将每一段值处理到 simhash 结果,得到最后的 simhash 值。比较海明距离就可以大概知道两个文档的相似度了。
具体的算法懂得不多就不瞎说了……大概可以推测,对于长文档这种方法是有效的,但是对于短文本,如 password 来说,效果可能不会太好。

Facebook 的做法

事实上这个问题好奇的人也很多,Stack Exchange 上有一个回答 http://security.stackexchange.com/questions/53481/does-facebook-store-plain-text-passwords,下面有一个自称接触过密码验证这部分代码的人肯定了这个猜测。
我觉得这种做法看起来还是挺合理的。

Facebook 用了一种看起来很「土」的方法,操作方法类似这样:

  1. 用户注册,密码 abc123,Facebook 保存了 `hash("abc123")
  2. 用户修改密码,提交新密码 Abc123
  3. Facebook 拿到新密码,根据这个密码,生成一堆类似于 ABC123abc123 这样相近的密码,使用同样的 hash 方法,去和 1 中的 hash 比对,一旦发现有相同的,那么可以判定新密码与旧密码是相似的。

很好的反向思维,不是去计算相似性,而是通过生成一堆相似密码来「暴力」尝试。

其他想法

事实上最初想到这个问题的时候,我考虑过这样的做法:

  1. 用户修改密码操作时,提示输入原密码
  2. server 临时记录用户的原密码
  3. 用户输入新密码,server 比对新旧密码
  4. 完成修改或过期后,销毁临时记录

不过即使是临时记录依然可能存在风险,如果需要较高的安全性的话这种方法是不可取的。

无意中翻到 Joe Armstrong 发在 erlang-questions 里的文章,Ways to get started 以及 history of erlang
如果你不知道 Joe Armstrong 是谁,我们给他的另一个称呼是 the father of Erlang :)
大概没有人比他更有资格写这种文章了吧。
在高手眼中大道至简,我们不一定学的来,但是听听还是很有启发的

随便瞎扯几句

忘掉工具

Forget about git/IDEs/rebar etc.
Forget about the tools

如果没有 IDE,没有自动打包工具,我们怎么编写和运行代码?
记住,shell 和文本编辑器对任何语言都是适用的。
当然我并不觉得这意味着需要放弃 IDE 之类的工具,而是在 get started 的时候,对程序怎么工作的有基本的了解是有好处的。
某种意义上来说,过于复杂的工具链意味着,一旦它没有按照你想象的运行,就需要花费更多的时间去解决它。

  • rebar!

当然,不能忘了 rebar!
事实上 rebar 已经快要成为 erlang project 的标配了。

Tools like rebar etc are under to automate something but if you don't
know what it is that you are automating and if the tool doesn't work
you will just end up being incredible confused.

「像rebar这样的工具会自动生成一些东西,但如果你不知道自动生成了什么,如果这些工具无法使用了,你将会变得困惑不已。」
说得好!
但是在更好的解决办法出现之前,也只能这么用了,寄希望于 OTP 组的改进吧,这一块也是我最不喜欢 erlang 的地方。

我一直觉得好的语言应该是某种程度上符合直觉的。这种直觉也许来自逻辑也许来自经验。
比如 erlang。
要举个反例也很容易,比如「世界上最好的语言」。
Joe Armstrong 是这么不经意的黑

Notice there is no quick fix here - if you want a quick fix go buy
"learn PHP in ten minutes"
and spend the next twenty years googling for
"how do I compute the length of a string"

hmm, well done!

the father of Erlang

Joe Armstrong 是个有趣的老头,也是真正的大师,推荐他的 blog,内容远远不止 erlang,可以看他讲讲信手拈来言简意赅的道理,喜欢八卦的话可以看他学 js 顺手黑黑其他语言 :)
以及他的 twitter @joeerl

最后是一段以前放在 erlang.org 上的话,如果学完 erlang 你还不懂这段话,可能你需要从头再来一遍 :)

The world is concurrent.
Things in the world don't share data.
Things communicate with messages.
Things fail.
                      - Joe Armstrong

btw,Joe Armstrong 的邮箱地址是 erlang#gmail.com,是不是比 「I Wrote Python」 低调多了 :)

  • posted on 2015-08-22 01:14
  • erlang
Previous