浏览 1819 次
锁定老帖子 主题:浅析servlet线程安全性问题
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-05-23
servlet安全性问题,其实这在网上有很多资料供参考的,但是我还是要自己写一些东西,毕竟是自己在秋知道路上碰到的。 servlet默认是多线程的,它的生命周期是由Web容器负责的。当用户第一次请求某个servlet的时候,web容器先到web.xml文件中查找该servlet配置,然后找到servlet-class并实例化该servlet。而当当浏览器第二次请求该servlet的时候,web容器将不会再次实例化。即多个线程共同使用该servlet的实例。这就造成了一定的不安全因素,虽然这种不安全发生的概率不是很大,但是防范于未然是web开发中必须考虑到的。 下面为了突出servlet多线程在用户多次请求过程中突出的不安全性问题,给出一个例子。供参考。 import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestServlet extends HttpServlet { private static final long serialVersionUID = 1L; PrintWriter out = null; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("GBK"); //获取参数 String param= req.getParameter("param"); //获取out实例 out = resp.getWriter(); try { //让程序等待10秒钟后输出name Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } out.println("您传入的参数为:"+param+"<br>"); } } } web.xml配置 <servlet> <servlet-name>servlet</servlet-name> <servlet-class>TestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>servlet</servlet-name> <url-pattern>/getName.do</url-pattern> </servlet-mapping> 在这个servlet,我为了能顺利暴露出servlet多线程所存在的漏洞,用了sleep(10000)。下面我通过两个不同类型的请求来说明问题: 一、不同用户请求同一servlet ·用户1请求:Http://10.81.66.173/testApp/getName.do?param=p1 ---在10秒钟内,第二个用户再次请求该servlet---- ·用户2请求:Http://10.81.66.173/testApp/getName.do?param=p2 ---获取的结果是---- ·用户1请求的响应为: (空白) ·用户2请求的响应为: 您传入的参数为:p1 您传入的参数为:p2 二、同一用户在较小的时间间隔离多次请求统一servlet ·浏览器输入:http://10.81.66.173/testApp/getName.do?param=p ·然后拼命地按enter回车,然后等待输出结果: 响应结果为: 您传入的参数为:p 您传入的参数为:p 您传入的参数为:p 您传入的参数为:p 您传入的参数为:p ...略 可见,按了多少次,就显示多少个“您传入的参数为:p” 至于出现该问题的最终原因,网上其实也有解释,那就是java内存模型决定的。下面是我在网上截取的一段话(比我说得好,所以用别人的): 引用 Java的内存模型JMM(Java Memory Model)JMM主要是为了规定了线程和内存之间的一些关系。根据JMM的设计,系统存在一个主内存(Main Memory),Java中所有实例变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存(Working Memory),工作内存由缓存和堆栈两部分组成,缓存中保存的是主存中变量的拷贝,缓存可能并不总和主存同步,也就是缓存中变量的修改可能没有立刻写到主存中;堆栈中保存的是线程的局部变量,线程之间无法相互直接访问堆栈中的变量。
那么,既然servlet存在线程安全问题,那么如何设计安全的servlet呢?在这里普遍来就爱那个,有三种方式可以实现。但在实际使用中要酌情考虑。 ·实现 SingleThreadModel 接口 public class TestServlet extends HttpServlet implements SingleThreadModel 不过考虑到系统开销问题,这种方法不赞成使用,具体原因我在这里不想多数,大家可以到网上搜一下相关资料。 ·使用synchronized同步对共享数据的操作 synchronized(this){ out = resp.getWriter(); try { //让程序等待10秒钟后输出param Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } out.println("您传入的参数为:"+param+"<br>"); } 这种方法可以使用,但是不建议,毕竟同步会是系统的性能、吞吐量下降很多,而且还会造成多个用户的请求发生阻塞,相比来说,下面的办法更好。 ·避免使用实例变量,改为方法内的局部变量 简单的奖printwriter out = null,放在方法内定义即可。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |