DWR 报错:Error: java.lang.SecurityException, Session Error 和 Allocate exception for servlet 问题的解决办法

时间:2022-09-18 21:13:34

DWR Session Error问题的解决办法 


来源于百度文库:http://wenku.baidu.com/link?url=RltL4aB3-To1EDI-mG3K7Vz7LdFWERxdu0Mpw5f29nd59pw_-qUHwB1HGZcRCjfMsUXVbgZeYxaD0JN6_HPz9tay7Z2V6DN5F58dcq8QF37

  
问题情境再现 使用的Dwr版本2.0 
在一台服务器上的不同端口上部署了同样的程序(tomcat5.5.28 80端口,tomcat 5.5.28 8080端口) 
使用浏览器先后登陆80,8080端口的程序,都不注销,保持会话状态。 
然后浏览器切换到8080的一个使用了DWR ajax功能的页面上,浏览器弹出Session Error的提示。 
但是,如果切换到80端口的程序上,同样进入到一个使用了dwr ajax技术的页面上,没有Session Error的提 示。  
问题诊断: 
初步怀疑浏览器的问题。 
检查浏览器的cookie中的jsessionid的值。因为我们知道,Http协议本身是无状态的,服务器标识同一次会话的过程就是借助于cookie中的某个值或者通过url重写的方式来实现。这也是jsp程序的session原理。  
检查发现:cookie中存在2个sessionid项,sessionid的值不同。 
因为站点地址相同,url也相同(除了端口不同外),因此,浏览器“误”认为是同一个程序,把缓存的cookie项都发送回了服务器。  
然后再观测ajax请求的值,即http post或get的参数值如下: callCount=1 
page=/web/initRolePermission.action 
httpSessionId=3F5F7D7C14D40667FF126DC6F9038EE5 scriptSessionId=5B2B53E512648E78C92393E052589CA3859 c0-scriptName=adminRolePerAction c0-methodName=findPermission c0-id=0 
c0-param0=string:181 batchId=0  
在这里,务必注意 
httpSessionId=3F5F7D7C14D40667FF126DC6F9038EE5, 
实际上,一般情况下,httpSessionId和cookie中的jsession值是相同的。 
至于dwr组件中,为什么要加上httpSessionId,这是因为dwr开发团队考虑到了跨站攻击问题。因此,通过验证dwr ajax请求中的httpSessionId值, 来防止跨站攻击。  
在重现,诊断问题过程中,发现Session Error的信息是来自dwr ajax请求的响应中,抛出的异常是java.lang.SecurityException, 因此可以怀疑这个错误信息是源于dwr源代码中的。 
用Eclipse打开下载到的dwr源代码。搜索Session Error的信息,然后在org.directwebremoting.dwrp.Batch 类中找到了,其部分代码如下: /** 
* Check that this request is not subject to a CSRF attack * @param request The original browser's request 
* @param sessionCookieName "JSESSIONID" unless it has been overridden */ 
private void checkNotCsrfAttack(HttpServletRequest request, String sessionCookieName) { 
// A check to see that this isn't a csrf attack 
// http://en.wikipedia.org/wiki/Cross-site_request_forgery // http://www.tux.org/~peterw/csrf.txt if (request.isRequestedSessionIdValid() && request.isRequestedSessionIdFromCookie()) { 
String headerSessionId = request.getRequestedSessionId(); if (headerSessionId.length() > 0) { 
String bodySessionId = getHttpSessionId();  
// Normal case; if same session cookie is supplied by DWR and // in HTTP header then all is ok 
if (headerSessionId.equals(bodySessionId)) { return; }  
// Weblogic adds creation time to the end of the incoming 
// session cookie string (even for request.getRequestedSessionId()). // Use the raw cookie instead 
Cookie[] cookies = request.getCookies(); for (int i = 0; i < cookies.length; i++) { 
Cookie cookie = cookies[i]; 
if (cookie.getName().equals(sessionCookieName) && cookie.getValue().equals(bodySessionId)) { return; } }  
// Otherwise error 
log.error("A request has been denied as a potential CSRF attack."); throw new SecurityException("Session Error"); } } } 
仔细分析这段代码,即使在上述问题情境环境中,也不会出现Session Error的错误。 然后反编译正在使用的dwr类文件,找到batch类,代码却不同,代码如下: private void checkNotCsrfAttack(HttpServletRequest request) { 
if(request.isRequestedSessionIdValid() && request.isRequestedSessionIdFromCookie()) { 
String headerSessionId = request.getRequestedSessionId(); if(headerSessionId.length() > 0) { 
String bodySessionId = getHttpSessionId(); if(!bodySessionId.startsWith(headerSessionId)) throw new SecurityException("Session Error"); } } } 
该代码没有考虑到cookie中出现多个jsession的情况。  
到此,问题就发现并解决。 
由于dwr低版本的bug引起的,升级dwr版本即解决此问题。 可能,读者还有一个疑问:为什么该问题只出现在8080端口上。 
检查发现:80端口的cookie项(就是80端口产生的jsessionid出现在cookie项的最前面), 

这样在80端口上的程序访问中,dwr ajax请求中的httpSessionId和cookie项最前面的jsessionid值相同,在80端口上,就自然不会出现session error错误。

三、

严重: Allocate exception for servlet dwr
org.xml.sax.SAXException: Failed to resolve: arg0=-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN arg1=http://getahead.org/dwr/dwr30.dtd

这是因为添加的jar包是2.0版本的,但是却引用了3.0的dtd文件,所以报错了,改为如下配置即可:

[html] view plaincopyprint?
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"   
  3.     "http://www.getahead.ltd.uk/dwr/dwr20.dtd">  
  4. <dwr>  
  5.     <allow>  
  6.         <create creator="new" javascript="dwrDate">  
  7.             <param name="class" value="java.util.Date"></param>  
  8.         </create>  
  9.     </allow>  
  10. </dwr>