深度防范
深度防范原则是安全专业人员人人皆知的原则,它说明了冗余安全措施的价值,这是被历史所证明的。
深度防范原则可以延伸到其它领域,不仅仅是局限于编程领域。使用过备份伞的跳伞队员可以证明有冗余安全措施是多么的有价值,尽管大家永远不希望主伞失效。一个冗余的安全措施可以在主安全措施失效的潜在的起到重大作用。
回到编程领域,坚持深度防范原则要求您时刻有一个备份方案。如果一个安全措施失效了,必须有另外一个提供一些保护。例如,在用户进行重要操作前进行重新用户认证就是一个很好的习惯,尽管你的用户认证逻辑里面没有已知缺陷。如果一个未认证用户通过某种方法伪装成另一个用户,提示录入密码可以潜在地避免未认证(未验证)用户进行一些关键操作。
尽管深度防范是一个合理的原则,但是过度地增加安全措施只能增加成本和降低价值。
最小权限
我过去有一辆汽车有一个佣人钥匙。这个钥匙只能用来点火,所以它不能打开车门、控制台、后备箱,它只能用来启动汽车。我可以把它给泊车员(或把它留在点火器上),我确认这个钥匙不能用于其它目的。
把一个不能打开控制台或后备箱的钥匙给泊车员是有道理的,毕竟,你可能想在这些地方保存贵重物品。但我觉得没有道理的是为什么它不能开车门。当然,这是因为我的观点是在于权限的收回。我是在想为什么泊车员被取消了开车门的权限。在编程中,这是一个很不好的观点。相反地,你应该考虑什么权限是必须的,只能给予每个人完成他本职工作所必须的尽量少的权限。
一个为什么佣人钥匙不能打开车门的理由是这个钥匙可以被复制,而这个复制的钥匙在将来可能被用于偷车。这个情况听起来不太可能发生,但这个例子说明了不必要的授权会加大你的风险,即使是增加了很小权限也会如此。风险最小化是安全程序开发的主要组成部分。
你无需去考虑一项权限被滥用的所有方法。事实上,你要预测每一个潜在攻击者的动作是几乎不可能的。
简单就是美
复杂滋生错误,错误能导致安全漏洞。这个简单的事实说明了为什么简单对于一个安全的应用来说是多么重要。没有必要的复杂与没有必要的风险一样糟糕。
例如,下面的代码摘自一个最近的安全漏洞通告:
1 |
<?php |
2 |
|
3 |
$search = (isset( $_GET [ 'search' ]) ? $_GET [ 'search' ] : '' ); |
4 |
|
5 |
?> |
这个流程会混淆$search变量受污染*的事实,特别是对于缺乏经验的开发者而言(注:受污染变量,即在程序执行过程中,该变量的值不是由赋值语句直接指定值,而是来自其它来源,如控制台录入、数据库等。)。上面语句等价于下面的程序:
01 |
<?php |
02 |
|
03 |
$search = '' ; |
04 |
|
05 |
if (isset( $_GET [ 'search' ])) |
06 |
{ |
07 |
$search = $_GET [ 'search' ]; |
08 |
} |
09 |
|
10 |
?> |
上面的两个处理流程是完全相同的。现在请注意一下下面的语句:
1 |
$search = $_GET [ 'search' ]; |
使用这一语句,在不影响流程的情况下,保证了$search变量的状态维持原样,同时还可以看出它是否受污染。
暴露最小化
PHP应用程序需要在PHP与外部数据源间进行频繁通信。主要的外部数据源是客户端浏览器和数据库。如果你正确的跟踪数据,你可以确定哪些数据被暴露了。Internet是最主要的暴露源,这是因为它是一个非常公共的网络,您必须时刻小心防止数据被暴露在Internet上。
数据暴露不一定就意味着安全风险。可是数据暴露必须尽量最小化。例如,一个用户进入支付系统,在向你的服务器传输他的信用卡数据时,你应该用SSL去保护它。如果你想要在一个确认页面上显示他的信用卡号时,由于该卡号信息是由服务器发向他的客户端的,你同样要用SSL去保护它。
比如前面的例子,显示信用卡号显然增加了暴露的机率。SSL确实可以降低风险,但是最佳的解决方案是通过只显示最后四位数,从而达到彻底杜绝风险的目的。
为了降低对敏感数据的暴露率,你必须确认什么数据是敏感的,同时跟踪它,并消除所有不必要的数据暴露。在本书中,我会展示一些技巧,用以帮助你实现对很多常见敏感数据的保护。