三、竞争状态
竞争状态即Race Condition,它是第二类最常见的应用安全漏洞。在创建(更改)资源到修改资源以禁止对资源访问的临界时刻,如果某个进程被允许访问资源,此时就会出现竞争状态。这里的关键问题在于:如果一个任务由两个必不可少的步骤构成,不管你多么想要让这两个步骤一个紧接着另一个执行,操作系统并不保证这一点。例如,在数据库中,事务机制使得两个独立的事件“原子化”。换言之,一个进程创建文件,然后把这个文件的权限改成禁止常规访问;此同时,另外一个没有特权的进程可以处理该文件,欺骗有特权的进程错误地修改文件,或者在权限设置完毕之后仍继续对原文件进行访问。
一般地,在标准Unix和NT环境下,一些高优先级的进程能够把自己插入到任务的多个步骤之间,但这样的进程在Java服务器上是不存在的;同时,用纯Java编写的程序也不可能修改文件的许可权限。因此,大多数由文件访问导致的竞争状态在Java中不会出现,但这并不意味着Java完全地摆脱了这个问题,只不过是问题转到了虚拟机上。我们来看看其他各种开发平台如何处理这个问题。在Unix中,我们必须确保默认文件创建模式是安全的,比如在服务器启动之前执行“umask 200”这个命令。有关umask的更多信息,请在Unix系统的命令行上执行“man umask”查看umask的man文档。在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);
}
文章来源于领测软件测试网 https://www.ltesting.net/