1、计 算机安全技术COMPUTING SECURITY TECHNIQUES2009.2012. 02在默认情况下, JSP 是以多线程工作的,在网站并发访问的时候,这种特性无疑大大地提高了 Web 服务器的工作效率,这也是 JSP 比其他相似技术更优越的地方 。然而在编程的时候如果不时时注意这种多线程的安全问题,就有可以造成意想不到的后果 。某次在使用 JSP 开发一个基于 B/S 的无纸化考试系统的时候,就差点因此酿成大错 。以下是代码片段:组卷 function backWindow () window.history.back (-1) ;由于组卷的要求,设置了一个数组 sel ,把从题
2、库中提取的题目编号暂时保存在数组 sel 中,又由于在组卷的时候要随机抽题,并且在试卷显示时也要进行乱序处理 。于是定义了一个公用的方法 isUnique (int a ,x),其功能是判断 x 是否存在于数组中,如果存在,就返回一个 false 给组卷主程序,要求另选一个题号 。在单机运行时,一切正常,可是在多人操作时,就出现了致命的逻辑错误 。后来经过调试的思考,发现这段程序至少有两个严重的错误 。一是 sel 数组的定义位置,不应该放在全局变量区;二是 isUnique () 方法的定义也有问题 。要解决第一个问题,还要从 JSP 的工作原理说起 。在服务器端, JSP 是被转换为 Se
3、rvlet 字节码运行,而当 Web 服务器把 JSP 转换为相应的 Servlet 时,凡是在 中定义的变量会被分配在全局位置,在整个 Servle 生命周期都有效 。而Servlet 以多线程运行,每一个访问的客户会共享同一份Serverlet 进程,该 Servlet 进程为每一个来访的客户创建一个线程 。而当多于一个用户访问时,问题就来了,由于每个用户访问的都是同一份拷贝,当然使用的是同一个 sel 数组 。这关于 JSP 线程安全问题的思考周世忠(厦门软件职业技术学院,福建 厦门 361024)摘 要: JSP 中变量的定义有全局和局部之分,局部变量并不会带来安全问题,而对全局变量的
4、使用,就要慎之又慎 。内置对象 application 的使用要特别注意线程安全 。此外, JavaBean 的使用也要注意线程安全问题,特别是当scope 属性设置为 application 的时候 。关键词: JSP; 多线程 ; 安全 ; JavaBean; 内置对象Thinking about JSP Multithread-safeZHOU Shizhong( Xiamen Institute of Software Technology , Fujian Xiamen 361024)Abstract: Global and local variables defined in th
5、e JSP, local variables do not pose a security problem, and the use ofglobal variables, they can. Built-in object application using special attention should be thread safe. In addition, the JavaBean using should also pay attention to thread security problems, especially when the scope property to the
6、 application ofthe time.Key words: JSP ; multi-threading ; security ; JavaBean ; a built-in object作者简介: 周世忠 ( 1970-),男,讲师,硕士,研究方向:面向对象与软件工程 。收稿日期: 2011-11-1897电 脑编程技巧与维护电脑编程技巧与维护电脑编程技巧与维护电脑编程技巧与维护2012. 02样,严重的后果就可想而知了 。解决的办法也很简单 。就是把 sel 数组的定义移动 内 。在 内定义的变量是局部变量 。当 Web服务器把 JSP 转换为相应的 Servlet 时,把该范围内
7、的代码放在 services () 方法中 。因而在其中定义的变量也只在该方法的范围内有效 。这样一来,每位访问的客户端虽然运行的是同一份 Servlet,但却拥有各自的 service () 方法,因而也就不会造成冲突了 。总结经验教训,在 JSP 中使用变量要特别小心,否则就会造成严重的线程安全问题 。其实在 JSP 中可以使用的变量有几种 。其一为类变量,包括 JSP 的 9 大内置变量 request、response、session、application、out、config、exeception、page、pageContext 等 。这些变量除了 application 处都是
8、线程安全的 。其二为实例变量,实例变量是实例所有的,在堆中分配 。在 Servlet/JSP 容器中,一般仅实例化一个 Servlet/JSP 实例,启动多个该实例的线程来处理请求 。而实例变量是该实例所有的线程所共享,所以,实例变量不是线程安全的 。其三为局部变量,局部变量在堆栈中分配,因为每一个线程有自己的执行堆栈,所以,局部变量是线程安全的 。对于包含线程不安全的变量的访问,如果实在有必要,那么就一定要考虑线程的安全问题,做到提前妨患 。比如前面提到的 isUnique () 方法,其实这个方法放在这里也是不安全的 。如果实在要在这里定义,那么最好在前面加个 synchronized 关
9、键字,以做到线程同步 。但据有关材料介绍,启用同步操作会大大降低系统的性能,倒不如在 指令标志中加上 isThreadSafe=“ false“,以关闭其多线程机制,仅以单线程运行 。如下:可是这样虽然解决了线程安全问题,却把 JSP 最优秀的特性给屏蔽了,有点得不偿试 。于是考虑把该方法移入 JavaBean 中 。那么,移入 JavaBean 中就是线程安全的吗?要想在 JSP 中使用 JavaBean, JSP 引擎必须创建一个 JavaBean 对象,然后在 JSP 页面中才能调用这个创建的 JavaBean。在 JSP 中提供了 、和 等动作标记来实现对 JavaBean 的操作 。
10、当然也可以在程序中作用 JavaBean。如果在程序中使用 JavaBean,则要使用 import 指令将 Bean 引入,例如引入 MyBean,格式如下:如果通过这种方式使用 Bean,则仍然有可能存在安全问题,就要看在何时何地实例化这个 Bean 了 。因此,最好是使用 JSP 提供的几个动作标记来使用它,那么对它的安全性会更加可控一些 。下面是 useBean 动作标记的使用格式:其中, ID 是定义 Bean 对象的唯一标识 。当含有 动作标记的页面在服务器上执行时, JSP 引擎首先偿试在 pageContent 对象内查找具有相同 id 和 scope 的 JavaBean 实
11、例,如果有就将这个实例分配给客户,如果没有就根据 Bean的字节码文件,创建一个名字为 ID、作用范围为 scope 的新实例添加到 pageContent 对象中,并将 Bean 分配给用户 。为了考虑线程的安全问题,要特别注意该使用格式中的scope 属性参数 。当取值为 pagej 时, Bean 的作用范围是 page。也就是,同一个客户访问的每个页面的 Bean 对象是互不相同的,它们占用不同的存储空间,当客户离开这个页面时, JSP 引擎取消为该客户分配的 Bean,释放其所占的空间 。不同客户访问同一页面时, Bean 之间互不干扰 。当取值为 Session 时, Bean 的
12、使用范围是 Session。也就是,同一个客户在同一个 Web 服务目录的不同的 JSP 页面中,只要 Bean 的 ID 相同,作用范围为 session,该客户得到的Bean 是同一个 。也就是客户在某个页面修改 Bean 的属性,在其他页面,该 Bean 的属性会发生同样的变化;不同客户之间的 Bean 是互不相同的 。当取值为 request 时, Bean 的使用范围是 request。也就是,同一个客户在 request 作用范围内请求与响应页面之间共用一个 ID 相同的 Bean,请求响应完成时该 Bean 即被释放;不同客户的 Bean 互不相同 。取值为 applicatio
13、n 时, Bean 的作用范围是 application。也就是 Web 服务目录下所有用户共享一个 Bean,只要所有客户 、该服务目录下所有页面使用同一个 ID 的 Bean,它们的Bean 是同一个,任何客户对 Bean 属性的修改都会影响到其他用 。综上所述,用户只要考虑在可见范围内所访问的 Bean 属性的并发性问题,适当地考虑线程同步,就能很好地解决线程的安全问题 。参考文献1 周宏凯 . 基于 JSP 的网上训练与考评系统的设计与实现 .学位论文 硕士, 2004.2 许益成,周伟敏 . 浅谈 JSP 安全问题及解决方法 . 期刊论文 -电脑知识与技术 (技术论坛), 2005, (12) .98