作为一个稍懂web安全的开发人员,在接触安全的某个阶段被一个问题给迷糊了好久(其实现在也好不了多少),那就是为什么开发人员和安全研究员在某些问题的实践上会有那么一些沟壑?
比如…网站防CSRF(下称“防CSRF”)。
安全研究员给出防CSRF的方法一般就是三板斧:判断referer、验证码、token。[1]
但实际的开发情况中,开发者能做到判断referer都已经是阿弥陀佛了。
然后一大波绕过referer的CSRF被送上,顺带被漏洞报告者痛批“上帝啊判断referer太容易绕过啊苍天啊怎么开发者不用token啊耶稣啊怎么那么不注意安全啊”云云…
最近有机会在一个项目中强制从业务流底层定义防CSRF策略,似乎略微感受到这个沟壑存在的一些根由:
(1)开发者永远都是被业务主导;在业务流中混入安全逻辑容易被忽略或者不好做
业务主导则必须保证可用性,不把东西做出来就不是合格的开发。这个大前提下面,开发者的精力必然是放在这上面,安全防御有可能会被放在后面再考虑(甚至从不考虑),从而导致问题产生。
另外,如果每个表单提交业务流上都要写“if(token校验不通过){告诉用户校验不对}”这种安全逻辑代码,开发有可能会觉得烦琐,不干了。类 似情况也出现在各种水平越权漏洞中,只不过更头疼:当开发面对各种可变量、要穷尽所有检查代码逻辑分支时,有时候甚至会怀疑产品定义是不是有问题,这种不 好做更容易导致安全逻辑的忽视或者被绕过…
(2)开发之间的编程语言特性配合有时候不好贯彻最佳安全策略
比如token,安全给出的较佳看法是服务器生成一次性token绑定在session并且在提交时用服务端校验;但遇到大量场景需要使用ajax 交互的时候,服务器根本给不到一次性token,因为页面无刷新啊!结果不少后端框架内置的安全策略,在遇到这种无刷新页面情况下直接歇菜,容易出现 csrf;此时到了补救阶段真的只能靠判断referer来防御了。
也许有人问,效仿国内两大php论坛系统(dz、pw)、给一个绑定浏览器header和ip的固定token,用于ajax交互防御如何?虽然勉 强达到效果,但如果本身语言之间的配合设计不当,可能大把页面的js没法拿到一次性token,结果大量业务报错,导致不能接受此安全策略,还得返回判断 referer……
那解决或者缓和方法在哪?
(1)尽量将通用的防御安全逻辑抽离出业务层,让业务层仅关心特定的安全逻辑
比如说,利用AOP思想(面向切面编程)中的切面、框架中的hook、甚至最差放到所有程序都要运行的common代码中,让防csrf的代码给抽出业务层,做成通用防御自动启用,业务层不需要插入相关代码即可获得防御。如果出现特定的安全逻辑,再择机放回业务层。
有些水平越权的漏洞也可以用这个方法解决。比如在进入业务流之前强制检查url或表单中的相关参数是否为当前用户所允许访问,否就禁止运行这个业务流。
(2)设计阶段要考虑各编程语言的特性,强制定义安全属性贯穿其中,但又要适度精简部分安全特性取得安全平衡
比如无页面刷新,只能降级为绑定浏览器header和ip的固定token,但强制所有页面都必须有这么一个token可以被js访问得到;服务器也必须要判断referer + 固定token……以此来完成防CSRF
=======
参考:
[1]http://hi.baidu.com/monyer/item/2167ba35b86e2599b90c0362
转自:http://www.iirr.info/blog/?p=1294