防御性编程
此條目需要擴充。 (2017年12月6日) |
此條目需要补充更多来源。 (2017年12月6日) |
防御性编程(Defensive programming)是防御式设计的一种具体体现,它是为了保证,对程序的不可预见的使用,不会造成程序功能上的损坏。它可以被看作是为了减少或消除墨菲定律效力的想法。防御式编程主要用于可能被滥用,恶作剧或无意地造成灾难性影响的程序上。[1]
主要概念:若常式收到錯誤的資料,即便錯誤資料是由其他常式出錯所造成,此常式也不會受到傷害。[2]
防御性编程通常通过以下途径,从而提高软件和源码的质量:
- 提高工程质量——减少bug和问题
- 提高源码可读性—— 源码应该变得可读且可理解,并且能经受代码审计。
- 让软件能通过预期的行为来处理不可预期的用户操作。
值得注意的是,过度的防御性编程可能会预防不可能会发生的错误,这样将导致运行时间与维护的损耗。当源码中拥有过多异常捕捉和异常处理,这有可能导致结果不正确或者被隐藏。
安全编程 编辑
防御性编程有时也被计算机科学家称为安全编程(Secure programming)。潜在的软件缺陷可能会被黑客利用,而进行代码注入,拒绝服务攻击或其他攻击。
防御性编程与非防御性编程之间的区别在于,程序员不会对特定的函数调用或库的使用情况做假设。下面是一个例子:
int risky_programming(char *input){ char str[1000+1]; // 1000为内容,1为空终止字符串 // ... strcpy(str, input); // 复制输入 // ... }
当输入超过1000个字符时,该函数将会崩溃。一些新手程序员可能并不会觉得这是个问题,因为没有用户会输入这么长的字符串。实行防御性编程的程序员不会允许这样的错误,因为这段程序包含一个已知的bug,一个可能会导致缓冲区溢出攻击的漏洞。下面这个例子是一个解决方案:
int secure_programming(char *input){ char str[1000+1]; // 1000为内容,1为空终止字符串 // ... // 限制越界拷贝。 strncpy(str, input, sizeof(str)); // 当最后一个字符不为空终止字符串,我们可以选择只处理未越界的内容,或者直接停止程序 str[sizeof(str) - 1] = '\0'; // ... }
进攻式编程 编辑
进攻式编程(Offensive programming )是防御式编程( defensive programming)的子集,其思想为:在重点的代码处不应该一些错误进行处理。在实践中,只有来自于软件外部的错误应该被处理(如:用户的输入);理论上,软件自身和相关可控的数据是可信的。
可信内部数据的校验 编辑
过度防御式编程 编辑
const char* trafficlight_colorname(enum trafficlight_color c) { switch (c) { case TRAFFICLIGHT_RED: return "red"; case TRAFFICLIGHT_YELLOW: return "yellow"; case TRAFFICLIGHT_GREEN: return "green"; } return "black"; //万一发生其他输入值时,使用信号灯将不亮 }
进攻式编程 编辑
const char* trafficlight_colorname(enum trafficlight_color c) { switch (c) { case TRAFFICLIGHT_RED: return "red"; case TRAFFICLIGHT_YELLOW: return "yellow"; case TRAFFICLIGHT_GREEN: return "green"; } assert(0); // 认为这种情况不可能发生 }
可信的软件组件 编辑
过度防御式编程 编辑
if (is_legacy_compatible(user_config)) { // 策略:新代码可能不完全兼容“用户配置” old_code(user_config); } else { // 策略:新代码操作“用户配置”,可能出会错 // 一旦出错时,,使用旧代码处理 if (new_code(user_config) != OK) { old_code(user_config); } }
进攻式编程 编辑
// 完全信任新代码 new_code(user_config);
技术层面 编辑
下面是常见的防御式编程的技术。
理性地重用代码 编辑
如果源码是广为利用地且经得起测试的,那么重用代码将有助于减少bug。
然而,重用代码往往不是最好的方案,越是底层的代码(往往指框架),重用代码带来的潜在危害就越是大。重用过于复杂的代码将大大地增加代码的复杂度。
遗留代码 编辑
在重用旧代码、包、API、配置等事物前,我们必须思考这些事物是否值得被重用,思考这些是否会造成遗留问题。
遗留问题的产生,往往是因为旧的设计无法适应当今的需求,尤其旧的设计往往不是为了当今需求,因此开发和测试可能存在缺陷。
参见 编辑
- 计算机安全
- 健壯性 (计算机科学)
- 進攻式編程
参考文献 编辑
- ^ 1.3 什么是防御性编程?. 51CTO.com. 2008-08-29 [2013-03-16]. (原始内容于2013-04-06).
- ^ Steve McConnell. 軟體建構之道. ISBN 9789866800115.