【发布时间】:2022-01-24 20:24:04
【问题描述】:
我正在编写一个 Java 检测程序,它使用 Javassist (v3.26.0-GA) 的内置检测 API 来拦截目标程序中的所有方法调用。另外,我在这个程序中实现了一个 REST API 服务,使用 Java Spark 通过添加/删除转换器来发送启动/停止检测的请求,以及在检测期间获取截获的方法。
现在,当我尝试使用从 premain 附加的 Java 代理运行 WebGoat(一个开源 Spring Boot 应用程序)时,我无法成功拦截所有方法,并且在日志中,有一个 NotFoundException 被抛出Javassist。
WebGoat 中的几个类都发生了这个错误,它们都有一个相似的共同事实,即它们与 SpringCGLIB 有关。一些错误如下所示。
javassist.NotFoundException: org.owasp.webgoat.hijacksession.cas.HijackSessionAuthenticationProvider$$FastClassBySpringCGLIB$$88f1f22d
at javassist.ClassPool.get(ClassPool.java:430)
at com.sparrow.sptracer.core.transformer.AbstractMethodTransformer.transform(AbstractMethodTransformer.java:87)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:541)
at java.base/java.lang.ClassLoader.defineClass0(Native Method)
at java.base/java.lang.System$2.defineClass(System.java:2307)
at java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClass(MethodHandles.java:2439)
at java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClass(MethodHandles.java:2416)
at java.base/java.lang.invoke.MethodHandles$Lookup.defineClass(MethodHandles.java:1843)
at java.base/jdk.internal.reflect.GeneratedMethodAccessor44.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:507)
at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108)
at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
at org.springframework.cglib.reflect.FastClass$Generator.create(FastClass.java:65)
at org.springframework.cglib.proxy.MethodProxy.helper(MethodProxy.java:135)
at org.springframework.cglib.proxy.MethodProxy.init(MethodProxy.java:76)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:216)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
at org.owasp.webgoat.hijacksession.cas.HijackSessionAuthenticationProvider$$EnhancerBySpringCGLIB$$6ae99c75.authenticate(<generated>)
at org.owasp.webgoat.hijacksession.HijackSessionAssignment.login(HijackSessionAssignment.java:72)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:517)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:584)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:763)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1651)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:219)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:567)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:602)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1610)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1377)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:507)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1580)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1292)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:501)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:556)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:375)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938)
at java.base/java.lang.Thread.run(Thread.java:833)
javassist.NotFoundException: org.owasp.webgoat.hijacksession.cas.HijackSessionAuthenticationProvider$$EnhancerBySpringCGLIB$$6ae99c75$$FastClassBySpringCGLIB$$8c045873
at javassist.ClassPool.get(ClassPool.java:430)
at com.sparrow.sptracer.core.transformer.AbstractMethodTransformer.transform(AbstractMethodTransformer.java:87)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:541)
at java.base/java.lang.ClassLoader.defineClass0(Native Method)
at java.base/java.lang.System$2.defineClass(System.java:2307)
... similar stacktrace as above
javassist.NotFoundException: org.owasp.webgoat.session.UserSessionData$$FastClassBySpringCGLIB$$2b6b54bc
at javassist.ClassPool.get(ClassPool.java:430)
at com.sparrow.sptracer.core.transformer.AbstractMethodTransformer.transform(AbstractMethodTransformer.java:87)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:541)
at java.base/java.lang.ClassLoader.defineClass0(Native Method)
at java.base/java.lang.System$2.defineClass(System.java:2307)
... similar stacktrace as above
[IMPACTRACER-CORE] ERROR [2021-12-24 10:34:20]: NotFoundException on class 'org/owasp/webgoat/session/UserSessionData$$EnhancerBySpringCGLIB$$bbb61fe2$$FastClassBySpringCGLIB$$34cb52d3': org.owasp.webgoat.session.UserSessionData$$EnhancerBySpringCGLIB$$bbb61fe2$$FastClassBySpringCGLIB$$34cb52d3
javassist.NotFoundException: org.owasp.webgoat.session.UserSessionData$$EnhancerBySpringCGLIB$$bbb61fe2$$FastClassBySpringCGLIB$$34cb52d3
at javassist.ClassPool.get(ClassPool.java:430)
at com.sparrow.sptracer.core.transformer.AbstractMethodTransformer.transform(AbstractMethodTransformer.java:87)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
... similar stacktrace as above
我的猜测是 WebGoat 在其 Spring Boot 环境中使用 cglib 来动态生成字节码,而相应的类原本不包含在 WebGoat 的类路径中,所以javassist.ClassPool.get(className) 抛出了错误。
我创建 ClassPool 对象的代码如下。
String name = Descriptor.toJavaName(className);
try {
ClassPool cp = ClassPool.getDefault();
cp.childFirstLookup = true;
cp.appendClassPath(new LoaderClassPath(loader));
CtClass cc = cp.get(name);
Logger.debug("Checking class %s", name);
CtMethod[] methods = cc.getDeclaredMethods();
Logger.debug("Altering %d methods in %s", methods.length, wut);
for (CtMethod m : methods) {
// do some code insertion
}
bytecode = cc.toBytecode();
cc.detach();
} catch (NotFoundException e) {
Logger.error("NotFoundException on class '%s': %s", className, e.getMessage());
e.printStackTrace();
} catch (CannotCompileException e) {
Logger.error("Cannot compile class '%s': %s", className, e.getMessage());
e.printStackTrace(System.out);
} catch (IOException e) {
Logger.error("IOException while transforming class '%s': %s", className, e.getMessage());
} catch (Exception ex) {
Logger.error("Generic exception occurred while transforming class '%s': %s", className, ex.getMessage());
ex.printStackTrace(System.out);
}
当我尝试与 localhost:8080 上的 WebGoat 应用程序交互时发生上述错误,尝试使用 Java Spark REST API 发送具有特定 ID 的“start istrumentation”请求,因此每当我发送此请求时,它都会触发 inst.addTransformer方法来创建一个新的 Transformer 并将其添加到检测对象。
此错误的原因可能是什么?我假设 WebGoat 本身正在使用一些检测,这意味着我正在检测一个检测的应用程序,我不知道这是否可能。
任何见解将不胜感激。
【问题讨论】:
-
未找到的类是动态代理,Spring 框架大量使用这些代理来实现 AOP。 Spring 可以同时使用 JDK 动态接口代理和 CGLIB 代理,后者就是我们在这里看到的。也许您应该简单地忽略这些类型的类。它们实际上是动态创建的,因此得名。但它们是动态(子)类生成的结果,而不是字节码转换的结果。
-
@kriegaex 是的,我考虑过忽略那些动态生成的类,但我的应用程序的重点是在用户与 Web 应用程序交互时捕获每个方法调用(例如单击按钮等)。在这种情况下,是否可以忽略这些类型的动态生成的类?我想确保不会错过任何方法调用。
-
由于这些类只是动态代理,它们要么将调用转发到原始方法,要么首先/代替调用一些 AOP 或拦截器逻辑。无论哪种方式,您都不会错过任何重要的东西,这些代理更像是交换机或路由器,实际显示发生在其他地方。我建议你简单地尝试一个带有一两个方面的小游乐场项目。
-
如果我的建议能帮助您解决问题,请告诉我。然后我可以将 cmets 转换为您可以接受的答案,以便正式将问题标记为已回答。
-
@kriegaex 谢谢。它确实有助于澄清事情。我没有使用 Spring Boot 应用程序的经验,所以我想我将不得不进一步研究它是如何工作的。如果我只想忽略那些动态代理类,我应该如何更改Javassist代码
CtClass cc = cp.get(name);,我想我可以放一个if语句,但是我将如何检查字符串className是否是动态代理类?如果你能写一个答案,那就太好了!我会接受的。
标签: java spring-boot instrumentation javassist webgoat