background image

Java 服务器端编程安全必知

 一、概述
  编写安全的 Internet 应用并不是一件轻而易举的事情:只要看看各个专业公告板就可

  找到连续不断的安全漏洞报告。你如何保证自己的 Internet 应用不象其他人的应用那
样满是漏洞?你如何保证自己的名字不会出现在令人难堪的重大安全事故报道中?如果你
使用 Java Servlet 、JavaServer Pages(JSP)或者 EJB,许多难以解决的问题都已经事先解决。
当然,漏洞仍有可能出现。下面我们就来看看这些漏洞是什么,以及为什么 Java 程序员不
必担心部分 C 和 Perl 程序员必须面对的问题。
  C 程序员对安全漏洞应该已经很熟悉,但象 OpenBSD 之类的工程提供了处理此类问
题的安全系统。Java 语言处理这类问题的经验要比 C 少 20 年,但另一方面,Java 作为一
种客户端编程语言诞生,客户端对安全的要求比服务器端苛刻得多。它意味着 Java 的发展
有着一个稳固的安全性基础。Java 原先的定位目标是浏览器。然而,浏览器本身所带的
Java 虚拟机虽然很不错,但却并不完美。Sun 的《Chronology of security-related bugs and 
issues》总结了运行时环境的漏洞发现历史。我们知道,当 Java 用作服务器端编程语言时,
这些漏洞不可能被用作攻击手段。但即使 Java 作为客户端编程语言,重大安全问题的数量
也从 1996 年的 6 个(其中 3 个是相当严重的问题)降低到 2000 年的 1 个。不过,这种安全性
的相对提高并不意味着 Java 作为服务器端编程语言已经绝对安全,它只意味着攻击者能
够使用的攻击手段越来越受到限制。那么,究竟有哪些地方容易受到攻击,其他编程语言
又是如何面对类似问题的呢?
  二、缓存溢出
  在 C 程序中,缓存溢出是最常见的安全隐患。缓存溢出在用户输入超过已分配内存空
间(专供用户输入使用)时出现。缓存溢出可能成为导致应用被覆盖的关键因素。C 程序很容
易出现缓存溢出,但 Java 程序几乎不可能出现缓存溢出。从输入流读取输入数据的 C 代
码通常如下所示:
  char buffer[1000];
  int len = read(buffer);
  由于缓存的大小在读入数据之前确定,系统要检查为输入保留的缓存是否足够是很
困难的。缓存溢出使得用户能够覆盖程序数据结构的关键部分,从而带来了安全上的隐患。
有经验的攻击者能够利用这一点直接把代码和数据插入到正在运行的程序。
  在 Java 中,我们一般用字符串而不是字符数组保存用户输入。与前面 C 代码等价的
Java 代码如下所示:
  String buffer = in.readLine();

  在这里, 缓存 的大小总是和输入内容的大小完全一致。由于 Java 字符串在创建之
后不能改变,缓存溢出也就不可能出现。退一步说,即使用字符数组替代字符串作为缓存,
Java 也不象 C 那样容易产生可被攻击者利用的安全漏洞。例如,下面的 Java 代码将产生溢
出:
  char[] bad = new char[6];