现状:过多的“马后炮”
当前,关于计算机系统的安全讨论很热,无论是数据泄露,还是 DDoS 攻击,亦或是 system hijacks 等都为这个话题贡献了热度。与之相应,宣传销售间谍程序、防火墙等相关的安全公司在增多,并且,对“网络安全专业人士”的需求也在不断上涨。
虽然这些安全防护措施或许“物超所值”,但仍有不足:很大一部分的安全防护是在系统搭建完成后才添加的。如果服务易受攻击?没问题,加一个入侵检测系统来识别和过滤那些企图利用漏洞入侵的网络数据包。
无疑,这种做法很有吸引力,但可惜没啥作用。
正如计算机安全专家在 60 年代强调的,真正的安全要从系统设计构建时就开始考虑。等到系统部署完成后,这时才添加的安全措施有点像“马后炮”。
让安全成为软件开发必需的一部分
从开始就融入安全考量,现在有很多方法,例如“BSIMM(软件安全构建成熟度模型)”。Synopsys 和 Veracode 提供能筛查安全漏洞的代码分析产品。微软的“安全开发生命周期”、Gray McGraw 的《软件安全:让安全成为软件开发必需的部分》和 Sami Saydjari 发布的《可信系统工程》,这些指南均为如何设计、开发更好的系统指明道路。
这些方案都很不错,但还需要更重视软件开发过程中的安全性。
因此,我们需要更好的教育和训练。
今天,很多人重视性能,但仔细想想,安全难道和性能表现不是同等重要吗?
越来越多方便上手的脚本语言证明运行表现的重要性,而安全的重要性或将在日后得到证明。不可否认,很多安全漏洞本意是为良性环境编写的代码,最终却被应用到易被攻击的敏感环境中。因此,在讨论如何提升代码效率的同时也应经常提到代码的安全性。
一种可行的思路是,当开发者关注程序正确性和有效性的同时,应尝试在目标环境中编写程序。但这样还称不上安全,开发者写的代码必须能在所有环境中安全运行。
因此,无论是学生,还是普通的开发者都要搞清楚:程序中的 bug 如何被当做安全漏洞实施攻击,以及如何阻止类似漏洞产生。
安全漏洞
缓冲区溢出,它指当计算机向缓冲区内填充数据位数时超过缓冲区本身的容量,溢出的数据覆盖在合法数据上,以及因此带来的栈缓冲区溢出攻击(smashing the stack)。
这类攻击包括缓冲区溢出攻击和命令注入攻击(command injection)。它们都具备的一大特点是:
黑客欺骗程序将本应做为数据的输入当作是代码,并进一步执行这些恶意代码。
针对网页程序的弱点和对应的攻击方式,包括 SQL 注入攻击、跨站脚本攻击(XSS)、跨站请求伪造(CSRF)。
这类攻击的共同点和之前一样,都是黑客通过诱骗易受攻击的程序,将有问题的数据当作代码。这些代码可被用于劫持程序,盗窃机密,或是破坏重要信息。
代码防护
现在,关于大部分类似漏洞的防护措施都是针对“ a high level”。例如,在使用任何不被信任的输入前进行验证,确保输入数据的大小不会超过缓冲区容量,以此保证程序安全。
对前文提到的其他四种攻击,存在漏洞的程序会在 piecing 另一程序时一并执行恶意命令代码。举个例子,假设有个应用程序想得到用户的用户名和密码作为输入,然后 splicing 这些用户名和密码到一个 SQL 可查询数据库的模板程序里。不过,某些用户名或密码可能包含 SQL 命令,导致程序执行与查询本意不同的命令。
这种情况在构造 shell 命令或 JavaScript 或 HTML 程序(跨站脚本攻击)时都会遇到。这些攻击的防范措施同样针对“ a high level”,例如过滤潜在危险数据。
本文作者提到:目前,大多数计算机安全课程都会侧重漏洞利用,但重点可能在于如何修复应用程序中的安全漏洞。他用了这样的方法:给学生一款 Ruby 编写的有多个漏洞的 Web 应用程序,学生要在不破坏其核心功能的情况下修复这些漏洞。然后,根据自动评分系统对这些修复方案的功能性和安全性评分,并测试原有漏洞是否被修复。学生必须通过修改程序使其通过测试。
底层控制的安全
事实上,最危险的漏洞类型莫过于远程代码执行漏洞(ACE),它允许攻击者在目标系统上执行任何代码。类型不安全的语言(C/C++)中薄弱的内存管理机制会导致很多漏洞,诸如 ACE、释放后重引用(UAF)、二次释放和缓冲区溢出。
根据MITRE的通用弱点枚举(CWE)数据库,缓冲区溢出漏洞仍然是当今最大的漏洞类别。
用类型安全的语言(如 Java)编写的程序不会受到这类内存错误的影响,因此消除了很多漏洞。
注:这一点并不完全对,因为用 Ruby 或 Rust 编写的程序仍有部分是通过调用 C/C++的外部函数接口实现的。尽管如此,不使用 C/C++作为日常编程语言仍可以减少被攻击的可能性。
但是,这些类型安全的语言会使用抽象数据表现形式和 Garbage Collection。这虽然让编程变得更容易,消除底层控制,但同时也增加了有些“难以承受的开销”。
尽管无法容忍 the overhead 和缺乏控制,C/C++实质上仍是操作系统、设备驱动程序、嵌入式设备的唯一可选项。
现在,这些系统受到攻击的概率和频率不断增加,我们应该做什么呢?
Rust:不用 GC 的类型安全语言
2010 年,Mozilla公司开始了一个野心勃勃的项目:开发一门针对高性能程序的安全编程语言。这个项目为我们带来 Rust。
Rust 的开发始于 2006 年,但最初 Mozilla 并不支持 Rust。
在 Rust 中,类型安全( type-safety)通过各种警告保证程序不会出现内存错误以及 free of data races,而这种类型安全的保证不需要 garbage collection(GC),在这一点上,其他任何的主流编程语言都做不到。
2019 年 2 月初,微软一次演讲中提到,70% 的安全漏洞都是内存安全问题。此后 7 月份,微软安全响应中心(MSRC)发文表示:微软需要更安全的系统编程语言。此后的系列文章中,微软对自己为什么认为 Rust 语言目前是业界的最佳选择做了阐述。而在近日,微软透露了使用 Rust 代替 C/C++ 编写 Windows 组件的实验感受,工程师们直言使用 Rust 语言的感受妙不可言。
我的任务是对 Windows 代码库的一个低级别系统组件进行实验性重写(目前不能透露是哪个组件),虽然这个项目还没有完成,但总的来说,在 Rust 方面的试验体验是非常好 (generally positive)。新的组件或现有的具有干净接口的组件移植到 Rust 是很容易的。
软件安全必须作为开发的必需部分。同时,未来开发人员关于软件安全性的教育培训将为提高安全观念迈出重要一步。
英文原文:
http://www.pl-enthusiast.net/2018/08/13/security-programming-languages-issue/
评论