最近公司搬迁,所有虚拟机都要重新部署,累死了。然后 Python 一堆依赖以前没管理好,直接装全局位置,也忘记导出一份版本号到新机器来安装。这是祸根
换到新机器后,Skynet 和 Golang 相关应用都跑起来了。但是 Python 写的内部应用有点问题,网站认证后,认证用户名 valid_username 一直传不到应用里。检查过内部 Oauth 的代码,以及 Nginx 的转发配置,都没有问题。最终通过重放请求定位到是 Gevent 丢掉了这个参数。同事帮忙翻了下更新日志,发现因为安全问题,带下划线的变量不再传递了,参考 issue 819 和 issue 775
819很简洁的引用了 waitress 库 以及 Django,Apache 和 Nginx 的安全更新日志。原来,这是一个下划线和破折号自动转换引起的 WSGI header 欺骗攻击。在 WSGI 环境下,所有 HTTP 请求头会全部转换为大写字母,所有破折号转换成下划线,并添加HTTP_ 前缀。例如,X-Auth-User 会转换成 HTTP_X_AUTH_USER
这意味着,WSGI 环境无法区分带有破折号的请求头和带有下划线的请求头。比如,为了防止访客伪造请求,我写了过滤规则,将客户端发来的 X-Auth-User 变量都干掉。但是,对方有可能发的是 X-Auth_User,最后依然可以转化成 HTTP_X_AUTH_USER,从而绕过安全认证
这个攻击是CVE-2015-0219,为了防止这种攻击,各大框架都加上了过滤下划线请求头的功能。内部应用还是用的带下划线请求头,所以触礁了。。。也就是说,以前的应用一直有安全漏洞,valid_username 请求头可能被伪造。当然,正常登录后,也是用 valid_username 来传递信息的,这个也要改掉,WSGI 不分敌我的干掉了。。。
Golang 里还是照样可以使用下划线,因为 Golang 没有 WSGI 这货,天然就可以作为 Web 服务器跑起来。有篇爆栈的文章解释为什么 Golang 不需要 WSGI