« February 2018 | Main | April 2018 »

March 15, 2018

为什么用本地程序通过本地端口做第三方服务认证是不安全的

今天有同事吐槽钉钉的 windows 客户端做第三方服务权限认证的流程,人机交互方面远没有 qq 好用。

我说,通过一个普通权限的本地程序做统一认证,其实是很容易出安全漏洞的,小心点比较好。一般来说,这个在操作系统层面支持会比较安全,就像 windows 的 UAC 。这种通常是第三方应用向服务器发一个认证请求,然后服务器下转发到本地客户端,然后客户端弹出一个确认窗口,经过用户确认以后,再经由第三方服务器下发给那个第三方客户端。

这里有个安全隐患就是,如果这个弹出窗口不是操作系统级别支持的话,在 windows 下很容易被普通权限的同级程序拦截。当然也不是完全没有办法。比如预留一个用户认可的信息展示,好像信用卡那样的安全识别码;我没用过 qq ,听说 qq 是用用户自己的头像做防伪确认的。

不过,这套流程做起来比较麻烦,开放个第三方使用的话,需要第三方客户端/服务器都遵循一定的协议来做。而且第一次需要做一次账号绑定,需要用户在第三方应用里输入一次自己的 qq 号,或在 qq 中输入一次第三方账号。windows 下可以先用 FindWindow 找到 qq 客户端的窗口,然后用一个自定义消息把一个 token 或第三方的账号信息发过去,完成握手。

说到这里,同事说,qq 的那套似乎没那么复杂,好像是走的本地端口。我先想说不至于吧,但是似乎每次遇到安全问题,我都会高估腾讯的产品设计人员的安全意识下限。腾讯系产品的用户权限大量被盗用似乎在黑产链上不足为奇。

我的机器上没有安装 qq ,不过我从网上搜到了这个:QQ快速登录的实现原理 。果然,qq 客户端在本地监听了 4300 端口,然后用 http 协议做的第三方认证。甚至都不是 https 。

如果还不确认,可以 ping 一下文中那个地址 localhost.ptlongin2.qq.com 解析出来就是 127.0.0.1 。

为什么这是相当不安全的?

因为本地端口是无法被操作系统权限管理的,也就是防火墙 uac 这些都无法警告和限制你有一个不相关的应用程序正在调用你的认证程序( qq 客户端)。如果用本地管道可能好点,在 linux 下可以通过文件权限控制来限制,不知道 windows 下是否能做到;但本地 socket 端口肯定是做不到权限控制的。

过去 windows 下非系统层的窗口不需要什么权限就可以被平级的程序拦截,现在不知道会不会好点。

即使认证窗口未被拦截,因为这里是不经过服务器,第三方应用根本不需要由腾讯官方授权,也不需要独立授权的证书,伪造一个请求过于容易。弹出的认证窗口上也没有说明这次认证申请的是哪些权限。这样,360 或类似竞争对手公司只要能安装一个客户端程序到用户的机器上,而用户开着 qq ,就能轻易获得用户的 qq 权限了。


如果走服务器认证的话,我认为可以把本地端口用于两个本地应用程序做绑定交互,简化绑定流程。这样安全危害小的多。因为绑定流程只用做一次,且可以用更安全(但繁琐)的程序。

March 14, 2018

LoadLibrary 无法加载 DLL 的 bug 处理

今天我们的小伙伴在把 Open Asset Import Library 封装成 lua 库的时候遇到一些麻烦。他在 vs 集成环境中编译的版本可以用,在 mingw-gcc 下却出错,报告 “找不到指定的模块。” 或是 “找不到指定的程序。" 。

我不得不吐槽,微软真是太有钱了,雇了一大帮人把出错信息都给国际化,这叫中国程序员怎么 google 问题啊。不太懂 windows ,反正我用 export LANG= 切换了 locale 为 C 还是不能把这段用 FormatMessage 格式化出来的 GetLastError 获得的出错码的错误串变成英文。还请读者中的 windows 大牛在留言中赐教。写这篇 blog 的主要目的就是以后有人可以用上面的出错信息关键词 google 过来。让我们一起来吐槽微软。

不过经验告诉我,不管是模块找不到还是什么程序找不到,这是 DLL 依赖问题。DLL 缺失这种问题,Dependency Walker 可以查。这个工具最早在 VC 里就自带,现在也能找到单独下载。不过安装了 mingw/msys 的话,我更喜欢用 ldd 。是的,linux 下的神器 ldd 现在有 windows 版了。

我前段发的 iup 的项目 iupmingw 就有同学碰到过类似的问题:https://github.com/cloudwu/iupmingw/issues/1

不过这次并不是缺少 dll ,为了观察 windows 的加载 dll 过程,它居然不报告到底在哪个环节出错,找不到 dll 也不报告文件名,我动用了另一个神器 ProcessMonitor ,推荐给大家使用。它可以监控进程的系统调用,比如加载动态库呀,打开文件啊,打开注册表啊。有了这个,windows 下写程序就不再是两眼一抹黑了。什么文件删不掉,看看谁锁住了它,用这个都能查到。可是为啥 windows 会有那么多文件锁住不准删这种事呢?

回头来看看 "找不到指定的模块。" 这条信息吧,它的 Error Code 是 126 ,英文是 The specified module could not be found 。用直白的话讲就是某个依赖的 dll 找不到。

"找不到指定的程序。" 这条信息的 Error Code 是 127 ,英文是 The specified procedure could not be found 。用直白的话讲是 dll 都找到了,但是 dll 里需要的符号找不到,通常就是版本有问题。

本文最初的问题应该是在构建的时候混用了 mingw gcc c++ 的 sjlj 和 seh 的异常处理 dll 导致的。这就是另一个话题了。