产品安全设计十大原则
原则1:最小化攻击面:
系统每增加一个功能特性就有可能会引入新的风险,通过安全开发可以减少攻击面进而达到控制系统整体风险的目的。
打个比方说,某在线web应用向用户提供了一个通过搜索来获取帮助的功能,如果后端代码没有正确实现该功能就有可能导致存在SQL注入漏洞,但是即便如此,我们还是有办法降低或消除风险的,比如:
u 该帮助功能只能被授权的用户使用。
u 后端代码对用户输入的数据进行了校验。
u 帮助功能不支持搜索,只支持查看。
可以看到,以上的第一、二点收缩了攻击面,即增加了攻击条件,减少了可以攻击的人数,而第三点则完全避免了风险,即攻击面完全消除了。其中第三点符合“简化系统设计”的原则,即不增加不必要的功能模块和特性。
原则2:Secure default:
在软件领域的含义就是:让默认的配置和策略尽可能的安全。比如,在许多场合,安全和产品体验经常会发生冲突,这时候应当选择安全优先,在安全的前提下,可以允许通过手动关闭安全配置或策略来提升产品体验。
比如,产品应该默认打开密码复杂度策略,即不允许用户使用不符合密码复杂度策略的密码,但产品可能可以允许用户关闭这个策略来提升体验。
注:只有充分了解业务安全需求的前提下,才能更好的使用该原则。
原则3:权限最小化:
事物只拥有可以完成他们任务的最小权限,即不赋予不必要的权限。包括但不限于:用户权限和资源权限(比如可以使用的CPU、内存、网络流量和存储容量等等)。
比如,某中间件服务器只需要访问网络、读取数据库和向日志服务器写日志的权限,那就完全没有必要赋予其更多其它的权限(特别是管理级别的特权)。
原则4:纵深防御:
从不同的维度去实施安全保护措施来缓解被攻击的风险。实施纵深防御策略,可以让攻击变得更加难以实施,漏洞变得更加难以利用。
比如,为了防止或减少SQL注入带来的危害,我们可以:
u 在应用外围部署WAF。
u 应用对输入数据进行有效性验证或进行参数化查询。
u 数据库连接账户隔离以及权限最小化。
u 敏感数据加密存储。
u 对数据库进行安全配置或关闭不必要的强大功能。
原则5:Fail securely:
即业务系统能够正确安全地处理各种异常和错误。错误样例代码如下:
isAdmin = true;
try {
codeWhichMayFail();
isAdmin = isUserInRole( “Administrator” );
}
catch (Exception ex) {
log.write(ex.toString());
}
当异常发生时,异常处理代码处理不当,可以导致普通用户直接提升为管理员用户。
原则6:不要信任第三方系统
不少产品需要和第三方的业务系统对接,并使用其提供的数据,但是一般情况下,我们是无法掌控这些第三方系统的安全设计和开发过程的,所以它们也可能会存在安全漏洞,进而被人攻击,因此,我们必须充分考虑到当第三方系统被攻击时,如何保障自己的业务系统的安全性。
比如:当我们向第三方系统查询数据时,必须对数据进行有效性验证后才可以使用(比如使用这些数据进行数据库查询或显示到用户浏览器上)。
原则7:业务隔离:
基本思想是将业务系统尽分成尽可能多的独立单元,但某个单元出现安全缺陷时,可以将损害程度降到最低,通俗地说,就是不要把所有鸡蛋都放在一个篮子里。
比如:将具有核心数据的业务和BBS部署在同一个服务器上,很多BBS站点都使用开源系统(比如 discuz)搭建,经常爆出各种漏洞,一旦BBS被攻陷,将会威胁到核心业务数据的安全性。
注:隔离可以是系统内部功能模块之间的(比如:web服务器和数据库服务器等),也可以业务部署层面之间的(比如:BBS和核心业务)。
原则8:公开设计:
有些人认为,只要产品内部的实现细节不被外人知道,那么产品就是安全的,但其实这是一种保护效果比较差的方法。当然,并不是说这样做毫无意义,也的确增加了攻击的难度,但是不能对其形成过多依赖,甚至把它当成主要或唯一的安全防护手段。
比如:不少公司都实现了自己的私有加密算法,他们认为只要算法不被泄露或公开,那么算法就是安全的,但实际面临以下问题:
u 攻击者可以通过抓包或逆向二进制来进行破解。
u 攻击者通过入侵服务器或给员工机器种植木马的方式来获取到源代码。
u 对公司不满的员工故意公开算法。
一旦以上任意条件满足时,则这种不公开设计方式的保护也就变得没有意义,因此,正确地做法应该是:假设算法被破解或完全公开,同样能保证系统的安全。典型的案例诸如业界广泛使用的对称加密算法(AES)和非对称加密算法(RSA),它们的设计实现都是公开的,但是仍然是安全的。
原则9:简化系统设计
“最小化攻击面”和“简化系统设计”原则是相辅相成的,由于复杂的系统设计会导致攻击面变宽,所以如果存在多种系统设计方案,则应尽量选择最简单的那种方案。
原则10:正确地修复漏洞:
一旦漏洞被发现和确认,首先要找到测试它的方法和弄清产生根因,对于产生漏洞的代码,需要确认该代码是否也在其它产品或版本上使用,即需要对漏洞进行完整地排查和修复。