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

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

原创 尹国斌 2020-03-22
3594

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> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1583570924549> <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> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1583570924549> <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> <[ACTIVE] ExecuteThread: ‘0’ for queue: ‘weblogic.kernel.Default (self-tuning)’> <> <> <> <1583570924552> <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打上此补丁修正此问题。

详细参考:https://mp.weixin.qq.com/s/yzMnMmJRW38Ktp5u9BUXIw

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论