关于GitHub的漏洞

GitHub,目前世界上最知名的源代码托管平台以及代码协作平台,今天爆出了极大的漏洞,可以被轻易的篡夺任何代码库的权限。

经过分析,这个漏洞是由于开发人员对Rails的mass-assignment(批量赋值)使用不当造成的。

所谓批量赋值,从浏览器提交上来的表单中,会以model[field1]=value1&model[field2]=value2的形式提交上来,Rails中,会解析成一个关于model的Hash表,这样,可以直接通过这个Hash表来使用非常简单的方式更新数据库:

Rails当然早就注意到这种问题的存在,所以引入了attr_accessibleattr_protectedattr_readonly等方法来对可以批量更新的字段做过滤。但是在默认上是完全没有限制的。

然而,Github那么多优秀的工程师却偷懒或者因为某些原因,没有细致地保护数据表,造成了现在的后果。

然而大洋彼岸的工程师们则在讨论几个问题:

  • Rails该不该为Github误用mass assignment负责?
  • Github暂停了黑客的账号的行为是否正确?(该黑客仅仅随便提交了个代码到主分支,以及打开了一个已关闭的问题,并未造成太多影响)

这次Github被黑我也想到了在我们天朝所发生的大网站用户数据库泄露的事情,更要命的是,据说某些网站的用户密码是明文存储的。

所以很多人认为Rails应该弥补这个漏洞,对批量赋值的功能直接加以限制。我当然认为这是好事。但是我同样认为,框架加上的限制,对于使用者的偷懒和误用等等,是没有办法的。

例子有很多,第一个显著的例子是PHP,PHP有着各种各样的问题,但它就是一个非常热门的语言。有多少人在学习PHP的时候会去了解SQL注入呢?PHP的register_global也是臭名昭著的($_GET $_POST $SERVER中的key value会自动注册为全局变量,如果控制不当,很可能与自己的变量名冲突),我从我开始学习的时候,就从来没用过。但是,这无法阻止大部分新上路的,直接使用表单中的变量作为全局变量,因为觉得这样非常自然。

我对一些新学PHP的强调说使用一个成熟的框架,他们会觉得框架非常麻烦。当然一些高手会不屑的认为框架会束缚你,但初学者直接效仿高手,是错误的。

同样地,Rails内置的防范CSRF (Cross-Site Request Forgery,跨站请求)的功能,protect_from_forgery,我曾见过很多人把它是注释掉的,因为用了它,就必须在提交表单的时候加入一个authenticity token,很多新人不喜欢使用form_for,或者需要自己写表单、ajax的时候,就往往不知道怎么加或者懒得加,于是干脆直接注释掉拉倒。这样又多了漏洞了。

worse is better!

所以即便像PHP这样如此不安全,它还是非常流行,因为它简单方便,大家可以联想一下地铁的安检,许多人都认为地铁的安检是形同虚设的,有人对地铁安检非常反感,因为这大大地降低了地铁交通的效率。但事实上是因为大家并没有遇到过不安全的情况,不想为那些风险承担额外的麻烦。

人都是这样贱的,没事儿的时候,嫌麻烦,有事儿又嫌没事先提醒。没有经历过挫折就不会成长。这就好比前一段时间,很多老外都在嫌Rails过于臃肿,但是别忘了,在Rails刚出来没多久的时候,很多人嫌它功能不够丰富。

所以我认为,Rails框架增加一些安全措施固然很好,但真正让程序是否安全的,还在乎使用这个框架的开发人员。

这又让我联想起来,C和C++之间的一些辩论。很多人都诟病C的指针太过于灵活,容易出现的问题。看牛人是如何解释的
“C语言就像一把刻刀,简单,锋利,并且在技师手中非常有用。和任何锋利的工具一样,C会伤到那些不能驾驭它的人。”

The C language is like a carving knife: simple, sharp, and extremely useful in
skilled hands. Like any sharp tool, C can injure people who don’t know how to handle it.
This paper shows some of the ways C can injure the unwary, and how to avoid injury.
C Traps and Pitfalls*
Andrew Koenig

所以他们认为,不能因为刀有可能会伤人,就加入大量的元素(比如加个罩子啊,弄个开关啊等等),来防止他伤人,却限制了他本身的能力。
如果这样做,他就最终会成为一个专门的工具,比如料理机等等。这就不是一个专门的框架了。


与Github一样,博聆也用的是Rails框架,那么我们做的怎样呢?我已经在需要的地方加上了合适的限制,attr_protected和attr_accessbile。但是同样今天有朋友反映说,匿名回复,可能会在给被评论的用户发出通知中泄露用户的名字。

其实我是做了特别的保护的,使用普通方法,如post.user_idpost.user,当帖子为匿名时,这两个函数只会返回0和Guest用户,必须使用特殊的方法才能调用到真实的用户信息。当然,为了能正确地给匿名了的用户发送信息,有时会需要取得真实用户的,所以之前出现过一个Bug,当用户匿名发帖的时候,用户收不到任何通知,就是因为被当做Guest用户没有进行发送。

然而,在测试中也尚未重现这种泄露信息的问题,看来还需要进一步研究。

虽然现在博聆的功能,尚未成熟,漏洞也非常多,非常欢迎大家来帮我进行测试。我也会尽我最大努力,将各方面完善起来。

发表评论

电子邮件地址不会被公开。 必填项已用*标注