【注】本文所说的“实现”,狭义的理解它就是“编程”,或者有的人习惯于叫“编码”。叫实现更准确,因为产品生产的过程,并不完全由编程来完成。
【观点一】理论上,无论是普通的Bug还是安全弱点,多数都是在程序实现过程当中引入的,严格的的执行良好的、正确的安全实现方法与原则,是确保产品安全的最最重要的一环,所谓的SDL及各种安全开发周期模型,其实它们只有一个最最显著的共性,那就是:将安全风险避免在安全现实的过程中。
【观点二】理论上,安全弱点与普通的Bug是没有区别的(而不是没有多少区别),比如:XSS的问题,那就是编码的不规范、不良习惯导致的结果:没有养成输出做filter的习惯。有人说这明明是为了解决安全问题而产生的编码原则,为什么说它与普通的bug成因是同因呢? 其实是同因的,比如:测试人员经常会在测试过程当中输入一些古怪的字符,导致UI显示异常、JS报错,这是大家熟悉的Bug吧?只是没想过它也可能是个安全问题而已,其实它就是XSS问题的前身嘛,通常有了这样的bug就意味着此处有XSS问题的风险。在企业没有引入安全开发流程时,并没有人把它理解为安全问题,只是头痛医头脚痛医脚的fix掉了,并没有系统的去解决这个问题而已。
OK, 好,进入正题。提到安全实现,往往是三大部分,千万要区分开来,以方便条理化的系统化的处理它,哪三部分呢?
1. 基于安全原则的安全实现 2. 基于语言特性的安全实现 3. 基于平台特性的安全实现
我想了想,只想出来这么多,可能按我个人脑子里的已知的内容来说,基本上也就这么多了。
【基于安全原则的安全实现】
输入
记得我第二篇文章里提到一个很重要的原则:输入验证–避免50%(只是经验值)以上的应用安全攻击,我看了一下本文在我所有文章当中创下了两个最:阅读量最小、参与评论最少。这恰恰反应我们的应用安全的现状:更重视可见的、可以轻易用数量度量的应用安全工作,而轻视不易度量的、无形的、价值更高的及对企业利益更高的应用安全工作。当然,这不完全是我们同行的错,这是高层的认知问题导致的结果。之所以说:不完全,那是因为咱们也有义务与责任去说服高层:-)。
以上这段我想表明一个原则就是:不要相信来自于你的代码可控制的以外的任何数据,除非你的代码有办法证明它的来源是可信的。
输出
记得我我在文章XSS解决方案系列 中提到输出验证的问题,由于本系列文章涉及的内容是广为人知的XSS问题,所以关注的人较多。通常情况下,输出意味着你的程序把数据递交给了下一道工序,请问:你知道下一道工序如何使用你的数据吗?有什么最基本的要求吗? 你可能回答:我不大清楚,我只知道个大概。OK无论你知道是详细还是概要,请都将你所能确定的部分考虑进来,以作输出时的格式、章法的限定依据,XSS的问题解决方案同样也是遵循此原则而得。有人说:输入验证做好了,输出的时候,还用管它是什么样子吗?其实不然,你们各司其职,可能在细节上存在重复,这种宁可有所重复也不可遗漏的应用安全思维习惯非常值得推崇。
以上这段想表达的原则:对于你的程序的输出,永远的尽可能的约束到可以约束的程度再递交到你的下一个流程当中
业务逻辑
提到业务逻辑,我就想说说腾讯的QQ系统产品当中的业务逻辑上的问题(没有诋毁之意,相反,这么庞大的产品套件,能做到这样已经非常难得)。曾经QQ上有一个陌生的无赖,想向我打听某个我熟悉的人的个人信息,我是做应用安全的,有职业的敏感性,没有配合对方,而是识别出对方其实是想做“社会工程学攻击”。当时没有多想,直接就没理对方,告诉对方我不知道,打听别人的消息是不好的。结果,不到一周,有同学打电话给我,说:你的故事不少嘛? 我说:啥故事? 对方说:你不是和谁谁有故事的嘛,是谁谁谁告诉我的。我突然明白了,是那个无赖透过“朋友网”、“QQ空间里的评论”及”微信平台“找到了许多我的朋友,并加他们为好友,了解我的情况,并在他们面前诋毁我,对于这种无赖,我没有兴趣与之过招,我用一个最简单的办法:关闭朋友网帐户、关闭微信、关闭QQ空间及拉黑这个无赖的QQ,这样我和几个已经上当的几个同学打个招呼告诉他们这个人是个无赖,骗子,此事就此算了。应该没有骚扰我的招了吧?确实,对方无法通过我的人脉关系对我进行骚扰,但是这是个极度无聊的人,其竟然通过:QQ空间申请访问时的留言、QQ客户端里的最近联系人列表里的我(我拉黑对方后,这个列表里的我 并不消失),不停的向我发送垃圾信息,你可能会问:加入黑名单的人,应该不能向你发送消息了吧? 这就是我要说的问题所在:
1. 自己已经在对方黑名单里,为什么还允许打开消息发送对话框,并允许发消息呢? 2. 自己已经在对方的黑名单里,为什么在最近联系人列表里还有对方呢? 3. QQ的PC客户端确实收不到黑名单里的人发来的临时消息,但是手机QQ客户端却可以收到,甚至还可以收到空间里的申请访问时的留言
OK,这些问题交给QQ的同行解决吧,我通过客服告诉了他们,不过没有一个客服理解我说的是什么,只是告诉我:删除垃圾消息吧,亲。
不管了,咱也不想挣什么漏洞报告的分子钱,呵呵,我只是为了引入的两个原则出来了:
1. 与业务逻辑有关的认证与授权控制,应该以数据对象本身为核心制订,而不是由数据对象的使用者的认知来决定 2. 认证与授权应由服务端完成,而非客户端
OK, 以上是关于产品实现过程的安全原则的宏观阐述,如果你理解我的意图,一定会有具体产品实现当中相关的问题,我们可以一起讨论,如果没理解我的意图,就如我自认为价值很高且操作性很强的文章:输入验证–避免50%(只是经验值)以上的应用安全攻击一样,这本身也同样给了我一个更有意义的反馈。
【基于语言特性的安全实现】
关于基于语言特性的安全实现,细说可能是一本书,只为抛砖引玉,我可能本文就可以指条明确的路。
问题一:
Windows经常出现的远程代码执行的漏洞,内部产生的机理是什么?
不知道你是否在日常工作当中涉及到unsafeC,我想windows经常出现的远程代码执行的漏洞的一个重要根源就是:unsafeC的使用,基于此,微软出台了MS-SafeC的库,也表明,早微软意识这个问题的严重性,但是windows 代码量如此庞大,完全做SafeC替换谈何容易?我相信微软后续开发的新产品(且不使用老的Lib库)应该解决了此类问题。
这就是我要说的基于语言特性的安全实现的问题,就拿C语言来说,由于它提供的大量的C函数,而部分C函数先天的没有要求开发的人员对输入进行校验,从而导致各种缓冲区溢出问题,我就归结为“基于语言特性的安全实现”问题,基于此,针对每一种语言,我们都需要花大精力研究一整套的语言安全使用规范,让所有的开发人员理解并学会使用安全函数,以达到安全实现。
问题二:
PHP为什么易出现代码注入问题?
相信这个问题同行都比较熟悉,至少,使用eval函数是重要的原因之一。而这类函数的存在与使用,就是与语言本身的特性有关,需要企业内做应用安全的人花足够的精力形成与语言特性有关的安全研究,以方便实施到企业安全开发流程当中。
不能每一种语言都举上一例,我也不是对每一种语言都精通,不过技术不是问题,不知道可以学,应用安全的思维方式最重要,因为有了它,对未知的部分你知道从哪开始去学并能快速掌握其精髓。
【基于平台特性的安全实现】
这一部分,在我所在企业当中,不归属于应用安全团队的责任范围,而归属于狭义的“信息安全”团队,也有人叫”IT Security”,他们负责公司的从法律层面、平台安全性评估、跟踪、平台安全事件的应急响应以及企业攻击事件的应急响应。这一部分不归我们负责,但不等于不知道如何做,思路完全一样,那就是:研究本企业产品所使用的平台、平台特性、常见的安全漏洞类型及通用的安全配置方案,关注行业最新动态,随时更新自己的平台及平台配置。
象最近暴露出的Struts的问题、之前暴露出的tomcat的问题,其实关注一些欧美安全服务提供商的站点的人,可以更早的知道并立即使用应急解决方案在自己的产品当中先临时处理,可以尽可能的避免由于信息滞后而带来的安全风险。
平台安全实现的相关要求、规范、版本控制、补丁策略等等都应该形成正式的文档,与产品一起发布,而不是滞后的研究。尽可能的保持测试环境与产品工作环境完全一致。
关于安全实现,先宏观的说这么多,细节太多,有兴趣的朋友,可以拧出一个关心的细节来,一起讨论一下。但是对于认可我的应用安全思维方式的同行,这样的描述我认为意义重大,至少可以理清思路,通过正统的渠道把应用安全工作有条不紊的做下去。