暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

WebLogic Server 10.3.6升级至p30463097后管理控制台登陆失败

东方龙马 2020-03-20
764


WebLogic Server 10.3.6升级至p30463097(JWEB|10.3.6.0.200114)后管理控制台登陆失败问题分析及临时处理办法。



案例背景
01
PART

Oracle 2020年1月发布了新一季的CPU,WebLogic Server 11g最新补丁版本代号JWEB,WebLogic Server版本10.3.6.0.200114。


在管理服务器侦听端口设定为80(http)/443(https)时,会出现以下问题:

1、服务器启动正常;

2、管理控制台登陆失败;

3、测试发现当管理服务器侦听端口设置为其它端口时,控制台可以登陆。

经过分析,最终确认为WebLogic Server 10.3.6.0.200114 Web Security Bug,影响的范围为使用基于JAAS Form (login-config\auth-method = FORM)登陆的应用。


临时解决的办法为通过weblogic.xml设定weblogic-web-app\container-descriptor\referer-validation为 NONE。


Oracle已经发布临时补丁Patch 18509293: SU Patch [EIL8]: 10.3.6.0.200114WLSPSU Overlay: CANNOT LOGIN TO CONSOLE, BUT CAN LOGIN TO EM WITH THE SAME USER来修正这个问题


详细的MOS DocID可参考:2637876.1



分析过程
02
PART

开启管理服务器调试:debug-http及debug-web-app-security为true,登陆失败时,AdminServer log有如下报错:

####<2020-3-7 下午04时48分44秒 CST> <Debug> <WebAppSecurity> <OLM-ET> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1583570924549> <BEA-000000> <ServletContext@613901058[app:consoleapp module:console path:/console spec-version:2.5] ChainedSecuirtyModule checking access with weblogic.servlet.security.internal.CertSecurityModule@56f42c88> 
####<2020-3-7 下午04时48分44秒 CST> <Debug> <WebAppSecurity> <OLM-ET> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<WLS Kernel>> <> <> <1583570924549> <BEA-000000> <ServletContext@613901058[app:consoleapp module:console path:/console spec-version:2.5] ChainedSecuirtyModule checking access with weblogic.servlet.security.internal.FormSecurityModule@2a2f5008> 
####<2020-3-7 下午04时48分44秒 CST> <Debug> <Http> <OLM-ET> <AdminServer> <[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'> <<anonymous>> <> <> <1583570924552> <BEA-000000> <HttpRequest@263621588 - console/login/LoginError.jsp: URI: console/login/LoginError.jsp>



可以确定在请求经过weblogic. servlet. security. internal.FormSecurityModule后被重定向至/console/login/LoginError.jsp;代码搜索weblogic. servlet. security. internal. FormSecurityModule,我们发现该类主要存在于以下两个路径:


J:\OLMJavaEEToolkit\classscanner>run.cmd
d:\OFM weblogic.servlet.security.internal.FormSecurityModule
J:\OLMJavaEEToolkit\classscanner>echo off
Search target directory:d:\OFM
Target class full name:weblogic.servlet.security.internal.FormSecurityModule
===========
file:/d:/OFM/patch_wls1036/patch_jars/BUG30463097_10360200114.jar
file:/d:/OFM/wlserver_10.3/server/lib/weblogic.jar
============



其中BUG30463097_10360200114.jar是实施p30463097后的补丁包,反编译weblogic.servlet.security.internal.FormSecurityModule代码,我们可以看到该处有j_security_check的处理过程


WebLogic Server 10.3.6.0.200114 weblogic.servlet.security.internal.FormSecurityModule
  
/*     */   boolean checkUserPerm(HttpServletRequest req, HttpServletResponse rsp, SessionInternal session, ResourceConstraint cons, AuthenticatedSubject waFormAuthUser, boolean applyAuthFilters)
/*     */     throws IOException, ServletException
/*     */   {
/* 208 */     if (req.getRequestURI().endsWith("j_security_check"))
/*     */     {
/* 215 */       return processJSecurityCheck(req, rsp, session);
/* 216 */     }if (waFormAuthUser != null)
/*     */     {
/* 219 */       return processLoggedInUser(req, rsp, waFormAuthUser);
/*     */     }
/*     */ 
/* 223 */     if ((this.webAppSecurity.isFullSecurityDelegationRequired()) && (this.webAppSecurity.hasPermission(req, rsp, null, cons)))
/* 224 */       return true;
/* 225 */     if ((applyAuthFilters) && (this.webAppSecurity.hasAuthFilters())) {
/* 226 */       invokeAuthFilterChain(req, rsp);
/* 227 */       return false;
/*     */     }
/* 229 */     if (isForbidden(cons)) sendForbiddenResponse(req, rsp); else
/* 230 */       sendLoginPage(req, rsp);
/* 231 */     return false;
/*     */   }


/*     */   private boolean processJSecurityCheck(HttpServletRequest req, HttpServletResponse rsp, SessionInternal session)
/*     */     throws IOException
/*     */   {
/* 239 */     if (!checkRefererHeader(req, rsp)) {
/* 240 */       sendError(req, rsp);
/* 241 */       return false;
/*     */     }
             ...
            }
            
/*     */   private boolean checkRefererHeader(HttpServletRequest req, HttpServletResponse rsp) {
/* 354 */     if (this.refererValidationType == RefererValidationType.NONE) return true;
/*     */ 
/* 356 */     String referer = req.getHeader("Referer");
/* 357 */     if ((referer == null) && (this.refererValidationType == RefererValidationType.LENIENT)) {
/* 358 */       return true;
/*     */     }
/* 360 */     if (referer == null) {
/* 361 */       return false;
/*     */     }
/*     */ 
/* 364 */     String[] refererAddr = extractRefererAddr(referer);//问题调用,referer=http://localhost/console/login/LoginForm.jsp,and only return refererAddr[0] = "localhost" ,and return false lead to checkRefererHeader failue.
/* 365 */     if ((refererAddr == null) || (refererAddr.length != 2)) return false;//return false
/*     */ 
/* 367 */     String serverHost = req.getServerName();
/* 368 */     int serverPort = req.getServerPort();
/* 369 */     int refererPort = 0;
/*     */     try {
/* 371 */       refererPort = Integer.parseInt(refererAddr[1]);
/*     */     } catch (NumberFormatException e) {
/* 373 */       return false;
/*     */     }
/*     */ 
/* 376 */     if (serverPort != refererPort) return false;
/* 377 */     if (serverHost.equals(refererAddr[0])) return true;
/*     */     try
/*     */     {
/* 380 */       return InetAddress.getByName(serverHost).equals(refererAddr[0]); } catch (UnknownHostException e) {
/*     */     }
/* 382 */     return false;
/*     */   }

    问题代码:referer=http://localhost/console/login/LoginForm.jsp时,只会返回长度为1的字符串数组
/*     */   private String[] extractRefererAddr(String referer)
/*     */   {
/* 387 */     int hostBegin = referer.indexOf("//") + 2;
/* 388 */     if (hostBegin <= 1) return null;
/* 389 */     int addrEnd = referer.indexOf("/", hostBegin);
/* 390 */     if (addrEnd < 0) return null;
/* 391 */     String refererAddr = referer.substring(hostBegin, addrEnd);
/* 392 */     return refererAddr.split(":");
/*     */   }



通过jdb调试还原问题过程,以下为调试信息:


[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)'[1] where
[1]weblogic.servlet.security.internal.FormSecurityModule.processJSecurityCheck (FormSecurityModule.java:240)
[2]weblogic.servlet.security.internal.FormSecurityModule.checkUserPerm (FormSecurityModule.java:215)
[3]weblogic.servlet.security.internal.FormSecurityModule.checkAccess (FormSecurityModule.java:98)
[4]weblogic.servlet.security.internal.ChainedSecurityModule.checkAccess (ChainedSecurityModule.java:79)
[5]weblogic.servlet.security.internal.ServletSecurityManager.checkAccess (ServletSecurityManager.java:82)
[6]weblogic.servlet.internal.WebAppServletContext.securedExecute (WebAppServletContext.java:2,219)
[7]weblogic.servlet.internal.WebAppServletContext.execute (WebAppServletContext.java:2,182)
  [8] weblogic.servlet.internal.ServletRequestImpl.run (ServletRequestImpl.java:1,499)
  [9] weblogic.work.ExecuteThread.execute (ExecuteThread.java:263)
  [10] weblogic.work.ExecuteThread.run (ExecuteThread.java:221)
  
  
[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1] dump this.refererValidationType
 this.refererValidationType = {
    NONE: instance of weblogic.servlet.security.internal.RefererValidationType(id=11841)
    LENIENT: instance of weblogic.servlet.security.internal.RefererValidationType(id=11842)
    STRICT: instance of weblogic.servlet.security.internal.RefererValidationType(id=11822)
    $VALUES: instance of weblogic.servlet.security.internal.RefererValidationType[3] (id=11843)
    java.lang.Enum.name: "STRICT"
    java.lang.Enum.ordinal: 2}



评析:

进入weblogic. servlet. security. internal. FormSecurityModule. processJSecurityCheck方法处理时,可以看到当前对象(weblogic.servlet.security. internal. FormSecurityModule)成员变量refererValidationType为STRICT; 



已完成的步骤: 

"线程=[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'", weblogic.servlet. security. internal. FormSecurityModule. checkRefererHeader(), 行=357 bci=21


[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1] where
[1]weblogic.servlet.security.internal.FormSecurityModule.checkRefererHeader (FormSecurityModule.java:357)
[2]weblogic.servlet.security.internal.FormSecurityModule.processJSecurityCheck (FormSecurityModule.java:239)
[3]weblogic.servlet.security.internal.FormSecurityModule.checkUserPerm (FormSecurityModule.java:215)
[4]weblogic.servlet.security.internal.FormSecurityModule.checkAccess (FormSecurityModule.java:98)
[5]weblogic.servlet.security.internal.ChainedSecurityModule.checkAccess (ChainedSecurityModule.java:79)
[6]weblogic.servlet.security.internal.ServletSecurityManager.checkAccess (ServletSecurityManager.java:82)
[7]weblogic.servlet.internal.WebAppServletContext.securedExecute (WebAppServletContext.java:2,219)
[8]weblogic.servlet.internal.WebAppServletContext.execute (WebAppServletContext.java:2,182)
[9] weblogic.servlet.internal.ServletRequestImpl.run (ServletRequestImpl.java:1,499)
[10] weblogic.work.ExecuteThread.execute (ExecuteThread.java:263)
[11] weblogic.work.ExecuteThread.run (ExecuteThread.java:221)
[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1] locals



方法参数:

req = instance of weblogic.servlet.internal.ServletRequestImpl(id=11846)

rsp = instance of weblogic.servlet.internal.ServletResponseImpl(id=11847)


本地变量:

referer = "http://localhost/console/login/LoginForm.jsp"

[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1]


评析:

进入weblogic.servlet.security. internal.FormSecurityModule. checkRefererHeader方法处理时,可以看到从报头上获取得到的Referer值为" http://localhost/console/login/LoginForm.jsp "并赋给局部变量referer;


[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1] where
[1]weblogic.servlet.security.internal.FormSecurityModule.checkRefererHeader (FormSecurityModule.java:365)
[2]weblogic.servlet.security.internal.FormSecurityModule.processJSecurityCheck (FormSecurityModule.java:239)
[3]weblogic.servlet.security.internal.FormSecurityModule.checkUserPerm (FormSecurityModule.java:215)
[4]weblogic.servlet.security.internal.FormSecurityModule.checkAccess (FormSecurityModule.java:98)
[5]weblogic.servlet.security.internal.ChainedSecurityModule.checkAccess (ChainedSecurityModule.java:79)
[6]weblogic.servlet.security.internal.ServletSecurityManager.checkAccess (ServletSecurityManager.java:82)
[7]weblogic.servlet.internal.WebAppServletContext.securedExecute (WebAppServletContext.java:2,219)
[8]weblogic.servlet.internal.WebAppServletContext.execute (WebAppServletContext.java:2,182)
[9] weblogic.servlet.internal.ServletRequestImpl.run (ServletRequestImpl.java:1,499)
[10] weblogic.work.ExecuteThread.execute (ExecuteThread.java:263)
[11] weblogic.work.ExecuteThread.run (ExecuteThread.java:221)
[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1] locals



方法参数:

req = instance of weblogic.servlet.internal.ServletRequestImpl(id=11846)

rsp = instance of weblogic.servlet.internal.ServletResponseImpl(id=11847)


本地变量:

referer = "http://localhost/console/login/LoginForm.jsp"

refererAddr = instance of java.lang.String[1] (id=11849)

[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1]

[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1]

[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1] print refererAddr[0]

 refererAddr[0] = "localhost"

[ACTIVE] ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)'[1]


评析:

执行至代码weblogic.servlet.security.internal.FormSecurityModule第365行(weblogic.servlet.security.internal.FormSecurityModule.checkRefererHeader),



故障结论
03
PART

可以看到,当referer = "http://localhost/console/login/LoginForm.jsp"时,从extractRefererAddr返回的字符串数组长度仅为1;代码weblogic.servlet.security.internal.FormSecurityModule第365执行完成的结果为return false;导致weblogic.servlet.security.internal.FormSecurityModule.processJSecurityCheck执行第240行sendError(req,rsp);


问题代码位于weblogic.servlet.security.internal.FormSecurityModule.extractRefererAddr。

可以确认此问题为10.3.6.0.200114的代码Bug。


根据代码weblogic.servlet.security.internal.FormSecurityModule.checkRefererHeader,如果weblogic.servlet.security.internal.FormSecurityModule.refererValidationType为NONE时,将会跳过Referer的检查;


参考weblogic.servlet.internal.WebAppConfigManager,refererValidationType默认值为LENIENT,可通过weblogic-web-app\container-descriptor\referer-validation进行设置。因此对于此问题的临时替代办法为:


设置$WL_HOME/server/lib/consoleapp/webapp/WEB-INF/weblogic.xml#weblogic-web-app\container-descriptor\referer-validation = NONE


根据Oracle的相关信息,Oracle发布了临时补丁Patch 18509293: SU Patch [EIL8]: 10.3.6.0.200114WLSPSU Overlay: CANNOT LOGIN TO CONSOLE, BUT CAN LOGIN TO EM WITH THE SAME USER来修正这个问题。可以在MOS上下载18509293打上此补丁修正此问题。






TiDB | 国产数据库

趋势所驱  拥抱开源

简单易用  面向未来


识别二维

查看更多课程详情



通过小程序快速下单

电话咨询:18501287439(同微信号)


TiDB相关资料

What’s New in TiDB 3.0.0 Beta.1

东方龙马与PingCAP大学正式达成合作,共同助力开源数据库生态建设

初级/高级 TiDB DBA线下培训报名开始了!

TiDB热火朝天,你愿跟随时代的脚步一起前进吗?

精华 | 5分钟了解TiDB (炙手可热的宠儿)

送惊喜 | TiDB DBA 官方指定培训·线下班限时特惠



|  北京    |    上海    |   广州    |   成都    |


4008-906-960



文章转载自东方龙马,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论