应用安全:JAVA反序列化漏洞之殇
应用安全:JAVA反序列化漏洞之殇
概述
- 序列化是让Java对象脱离Java运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化存储。
- Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的 writeObject() 方法可以实现序列化。反序列化是指把字节序列恢复为 Java 对象的过程,ObjectInputStream 类的 readObject() 方法用于反序列化。
漏洞成因
-
序列化和反序列化本身并不存在问题。但当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。
-
漏洞代码示例如下:
-
...... //读取输入流,并转换对象 InputStream in=request.getInputStream(); ObjectInputStream ois = new ObjectInputStream(in); //恢复对象 ois.readObject(); ois.close();
-
这里特别要注意的是非预期的对象,正因为此java标准库及大量第三方公共类库成为反序列化漏洞利用的关键。安全研究人员已经发现大量利用反序列化漏洞执行任意代码的方法,最让大家熟悉的是Gabriel Lawrence和Chris Frohoff在《Marshalling Pickles how deserializing objects can ruin your day》中提出的利用Apache Commons Collection实现任意代码执行。此后安全研究人员也陆续爆出XML、Json、Yaml等反序列化的相关漏洞。
-
除了commons-collections 3.1可以用来利用java反序列化漏洞,还有更多第三方库同样可以用来利用反序列化漏洞并执行任意代码,部分如下:
-
commons-fileupload 1.3.1
-
commons-io 2.4
-
commons-collections 3.1
-
commons-logging 1.2
-
commons-beanutils 1.9.2
-
org.slf4j:slf4j-api 1.7.21
-
com.mchange:mchange-commons-java 0.2.11
-
org.apache.commons:commons-collections 4.0
-
com.mchange:c3p0 0.9.5.2
-
org.beanshell:bsh 2.0b5
-
org.codehaus.groovy:groovy 2.3.9
-
……
Java反序列化详解
序列化数据结构
-
通过查看序列化后的数据,可以看到反序列化数据开头包含两字节的魔术数字,这两个字节始终为十六进制的0xAC ED。接下来是两字节的版本号0x00 05的数据。此外还包含了类名、成员变量的类型和个数等。
-
这里以类SerialObject示例来详细进行介绍Java对象序列化后的数据结构:
-
public class SerialObject implements Serializable{private static final long serialVersionUID = 5754104541168322017L;private int id;public String name;public SerialObject(int id,String name){this.id=id;this.name=name;}... }
-
序列化SerialObject实例后以二进制格式查看:
-
00000000: aced 0005 7372 0024 636f 6d2e 7878 7878 ....sr.$com.xxxx 00000010: 7878 2e73 6563 2e77 6562 2e68 6f6d 652e xx.sec.web.home. 00000020: 5365 7269 616c 4f62 6a65 6374 4fda af97 SerialObjectO... 00000030: f8cc c5e1 0200 0249 0002 6964 4c00 046e .......I..idL..n 00000040: 616d 6574 0012 4c6a 6176 612f 6c61 6e67 amet..Ljava/lang 00000050: 2f53 7472 696e 673b 7870 0000 07e1 7400 /String;xp....t. 00000060: 0563 7279 696e 0a .cryin.
-
序列化的数据流以魔术数字和版本号开头,这个值是在调用ObjectOutputStream序列化时,由writeStreamHeader方法写入:
-
protected void writeStreamHeader() throws IOException {bout.writeShort(STREAM_MAGIC);//STREAM_MAGIC (2 bytes) 0xACEDbout.writeShort(STREAM_VERSION);//STREAM_VERSION (2 bytes) 5}
-
序列化后的SerialObject对象详细结构:
-
STREAM_MAGIC (2 bytes) 0xACED STREAM_VERSION (2 bytes) 0x0005TC_OBJECT (1 byte) 0x73TC_CLASSDESC (1 byte) 0x72classNamelength (2 bytes) 0x24 = 36text (36 bytes) com.xxxxxx.sec.web.home.SerialObjectserialVersionUID (8 bytes) 0x4FDAAF97F8CCC5E1 = 5754104541168322017classDescInfoclassDescFlags (1 byte) 0x02 = SC_SERIALIZABLEfieldscount (2 bytes) 2field[0]primitiveDescprim_typecode (1 byte) I = integerfieldNamelength (2 bytes) 2text (2 bytes) idfield[1]objectDescobj_typecode (1 byte) L = objectfieldNamelength (2 bytes) 4text (4 bytes) nameclassName1TC_STRING (1 byte) 0x74length (2 bytes) 0x12 = 18text (18 bytes) Ljava/lang/String;classAnnotationTC_ENDBLOCKDATA (1 byte) 0x78superClassDescTC_NULL (1 byte) 0x70classdata[]classdata[0] (4 bytes) 0xe107 = id = 2017classdata[1]TC_STRING (1 byte) 0x74length (2 bytes) 5text (10 bytes) cryin
反序列化过程详解
- Java程序中类ObjectInputStream的readObject方法被用来将数据流反序列化为对象,如果流中的对象是class,则它的ObjectStreamClass描述符会被读取,并返回相应的class对象,ObjectStreamClass包含了类的名称及serialVersionUID。
- 如果类描述符是动态代理类,则调用resolveProxyClass方法来获取本地类。如果不是动态代理类则调用resolveClass方法来获取本地类。如果无法解析该类,则抛出ClassNotFoundException异常。
- 如果反序列化对象不是String、array、enum类型,ObjectStreamClass包含的类会在本地被检索,如果这个本地类没有实现java.io.Serializable或者externalizable接口,则抛出InvalidClassException异常。因为只有实现了Serializable和Externalizable接口的类的对象才能被序列化。
反序列化漏洞检测方案
代码审计
-
反序列化操作一般在导入模版文件、网络通信、数据传输、日志格式化存储、对象数据落磁盘或DB存储等业务场景,在代码审计时可重点关注一些反序列化操作函数并判断输入是否可控,如下:
-
ObjectInputStream.readObject ObjectInputStream.readUnshared XMLDecoder.readObject Yaml.load XStream.fromXML ObjectMapper.readValue JSON.parseObject ...
-
同时也要关注第三jar包是否提供了一些公共的反序列化操作接口,如果没有相应的安全校验如白名单校验方案,且输入可控的话就也可能存在安全问题。
进阶审计
-
对于直接获取用户输入进行反序列化操作这种点比较好审计并发现,目前反序列化漏洞已经被谈起太多次了,所以有经验的开发都会在代码中有相应的修复。但并不是所有修复都无懈可击。比如采用黑名单校验的修复方式,对于这种修复可在工程代码中尝试挖掘新的可以利用的’gadget‘。
-
代码中有使用到反序列化操作,那自身项目工程中肯定存在可以被反序列化的类,包括Java自身、第三方库有大量这样的类,可被反序列化的类有一个特点,就是该类必定实现了Serializable接口,Serializable 接口是启用其序列化功能的接口,实现 java.io.Serializable 接口的类才是可序列化的。一个典型的示例如下:
-
public class SerialObject implements Serializable{private static final long serialVersionUID = 5754104541168322017L;private int id;public String name;public SerialObject(int id,String name){this.id=id;this.name=name;}public void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{//执行默认的readObject()方法in.defaultReadObject();} }
-
所以在代码审计时对这些类也可进行特别关注,分析并确认是否有可能被发序列化漏洞利用执行任意代码。发现新的可利用的类即可突破使用黑名单进行校验的一些应用。
白盒检测
- 大型企业的应用很多,每个都人工去审计不现实,往往都有相应的自动化静态代码审计工具,这里以ObjectInputStream.readObject()为例,其它反序列化接口的检测原理也相似。在自动化检测时,可通过实现解析java源代码,检测readObject()方法调用时判断其对象是否为java.io.ObjectOutputStream。如果此时ObjectInputStream对象的初始化参数来自外部请求输入参数则基本可以确定存在反序列化漏洞了。这是只需确认是否存在相应的安全修复即可。 可参考lgtm.com对于Deserialization of user-controlled data检测方式的实现。
黑盒检测
-
调用ysoserial并依次生成各个第三方库的利用payload(也可以先分析依赖第三方包量,调用最多的几个库的paylaod即可),该payload构造为访问特定url链接的payload,根据http访问请求记录判断反序列化漏洞是否利用成功。如:
-
java -jar ysoserial.jar CommonsCollections1 'curl " + URL + " '
-
也可通过DNS解析记录确定漏洞是否存在。现成的轮子很多,推荐NickstaDB写的SerialBrute,还有一个针对RMI的测试工具BaRMIe,也很不错~。.
RASP检测
-
Java程序中类ObjectInputStream的readObject方法被用来将数据流反序列化为对象,如果流中的对象是class,则它的ObjectStreamClass描述符会被读取,并返回相应的class对象,ObjectStreamClass包含了类的名称及serialVersionUID。
-
类的名称及serialVersionUID的ObjectStreamClass描述符在序列化对象流的前面位置,且在readObject反序列化时首先会调用resolveClass读取反序列化的类名,所以RASP检测反序列化漏洞时可通过重写ObjectInputStream对象的resolveClass方法获取反序列化的类即可实现对反序列化类的黑名单校验。
-
百度的开源RASP产品就是使用的这种方法,具体可参考其DeserializationHook.java的实现:
-
@Overrideprotected MethodVisitor hookMethod(int access, String name, String desc,String signature, String[] exceptions, MethodVisitor mv) {if ("resolveClass".equals(name) && "(Ljava/io/ObjectStreamClass;)Ljava/lang/Class;".equals(desc)) {return new AdviceAdapter(Opcodes.ASM5, mv, access, name, desc) {@Overrideprotected void onMethodEnter() {loadArg(0);invokeStatic(Type.getType(HookHandler.class),new Method("checkDeserializationClass", "(Ljava/io/ObjectStreamClass;)V"));}};}return mv;}
-
其中检测覆盖的反序列化类黑名单如下:
-
plugin.register('deserialization', function (params, context) {var deserializationInvalidClazz = ['org.apache.commons.collections.functors.InvokerTransformer','org.apache.commons.collections.functors.InstantiateTransformer','org.apache.commons.collections4.functors.InvokerTransformer','org.apache.commons.collections4.functors.InstantiateTransformer','org.codehaus.groovy.runtime.ConvertedClosure','org.codehaus.groovy.runtime.MethodClosure','org.springframework.beans.factory.ObjectFactory','xalan.internal.xsltc.trax.TemplatesImpl']var clazz = params.clazzfor (var index in deserializationInvalidClazz) {if (clazz === deserializationInvalidClazz[index]) {return {action: 'block',message: '尝试反序列化攻击',confidence: 100}}}return clean })
攻击检测
-
通过查看反序列化后的数据,可以看到反序列化数据开头包含两字节的魔术数字,这两个字节始终为十六进制的0xAC ED。接下来是两字节的版本号。我只见到过版本号为5(0x00 05)的数据。考虑到zip、base64各种编码,在攻击检测时可针对该特征进行匹配请求post中是否包含反序列化数据,判断是否为反序列化漏洞攻击。
-
xxxdeMacBook-Pro:demo xxx$ xxd objectexp 00000000: aced 0005 7372 0032 7375 6e2e 7265 666c ....sr.2sun.refl00000010: 6563 742e 616e 6e6f 7461 7469 6f6e 2e41 ect.annotation.A00000020: 6e6e 6f74 6174 696f 6e49 6e76 6f63 6174 nnotationInvocat00000030: 696f 6e48 616e 646c 6572 55ca f50f 15cb ionHandlerU.....
-
但仅从特征匹配只能确定有攻击尝试请求,还不能确定就存在反序列化漏洞,还要结合请求响应、返回内容等综合判断是否确实存在漏洞。
Java反序列化漏洞修复方案
通过Hook resolveClass来校验反序列化的类
-
通过上面序列化数据结构可以了解到包含了类的名称及serialVersionUID的ObjectStreamClass描述符在序列化对象流的前面位置,且在readObject反序列化时首先会调用resolveClass读取反序列化的类名,所以这里通过重写ObjectInputStream对象的resolveClass方法即可实现对反序列化类的校验。这个方法最早是由IBM的研究人员Pierre Ernst在2013年提出《Look-ahead Java deserialization》,具体实现代码示例如下:
-
public class AntObjectInputStream extends ObjectInputStream{public AntObjectInputStream(InputStream inputStream)throws IOException {super(inputStream);}/*** 只允许反序列化SerialObject class*/@Overrideprotected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,ClassNotFoundException {if (!desc.getName().equals(SerialObject.class.getName())) {throw new InvalidClassException("Unauthorized deserialization attempt",desc.getName());}return super.resolveClass(desc);} }
-
通过此方法,可灵活的设置允许反序列化类的白名单,也可设置不允许反序列化类的黑名单。但反序列化漏洞利用方法一直在不断的被发现,黑名单需要一直更新维护,且未公开的利用方法无法覆盖。
-
SerialKiller 是由Luca Carettoni利用上面介绍的方法实现的反序列化类白/黑名单校验的jar包。具体使用方法可参考其代码仓库。
-
contrast-rO0是一个轻量级的agent程序,通过通过重写ObjectInputStream来防御反序列化漏洞攻击。使用其中的SafeObjectInputStream类来实现反序列化类白/黑名单控制,示例代码如下:
-
SafeObjectInputStream in = new SafeObjectInputStream(inputStream, true); in.addToWhitelist(SerialObject.class);in.readObject();
使用ValidatingObjectInputStream来校验反序列化的类
-
使用Apache Commons IO Serialization包中的ValidatingObjectInputStream类的accept方法来实现反序列化类白/黑名单控制,具体可参考ValidatingObjectInputStream介绍;示例代码如下:
-
private static Object deserialize(byte[] buffer) throws IOException, ClassNotFoundException , ConfigurationException {Object obj;ByteArrayInputStream bais = new ByteArrayInputStream(buffer);// Use ValidatingObjectInputStream instead of InputStreamValidatingObjectInputStream ois = new ValidatingObjectInputStream(bais); //只允许反序列化SerialObject classois.accept(SerialObject.class);obj = ois.readObject();return obj; }
使用ObjectInputFilter来校验反序列化的类
-
Java 9包含了支持序列化数据过滤的新特性,开发人员也可以继承java.io.ObjectInputFilter类重写checkInput方法实现自定义的过滤器,,并使用ObjectInputStream对象的setObjectInputFilter设置过滤器来实现反序列化类白/黑名单控制。示例代码如下:
-
import java.util.List; import java.util.Optional; import java.util.function.Function; import java.io.ObjectInputFilter; class BikeFilter implements ObjectInputFilter {private long maxStreamBytes = 78; // Maximum allowed bytes in the stream.private long maxDepth = 1; // Maximum depth of the graph allowed.private long maxReferences = 1; // Maximum number of references in a graph.@Overridepublic Status checkInput(FilterInfo filterInfo) {if (filterInfo.references() < 0 || filterInfo.depth() < 0 || filterInfo.streamBytes() < 0 || filterInfo.references() > maxReferences || filterInfo.depth() > maxDepth|| filterInfo.streamBytes() > maxStreamBytes) {return Status.REJECTED;}Class<?> clazz = filterInfo.serialClass();if (clazz != null) {if (SerialObject.class == filterInfo.serialClass()) {return Status.ALLOWED;}else {return Status.REJECTED;}}return Status.UNDECIDED;} // end checkInput } // end class BikeFilter
-
上述示例代码,仅允许反序列化SerialObject类对象,上述示例及更多关于ObjectInputFilter的均参考自NCC Group Whitepaper由Robert C. Seacord写的《Combating Java Deserialization Vulnerabilities with Look-Ahead Object Input Streams (LAOIS)》
黑名单校验修复
- 在反序列化时设置类的黑名单来防御反序列化漏洞利用及攻击,这个做法在源代码修复的时候并不是推荐的方法,因为你不能保证能覆盖所有可能的类,而且有新的利用payload出来时也需要随之更新黑名单。
- 但有某些场景下可能又不得不选择黑名单方案。写代码的时候总会把一些经常用到的方法封装到公共类,这样其它工程中用到只需要导入jar包即可,此前已经见到很多提供反序列化操作的公共接口,使用第三方库反序列化接口就不好用白名单的方式来修复了。这个时候作为第三方库也不知道谁会调用接口,会反序列化什么类,所以这个时候可以使用黑名单的方式来禁止一些已知危险的类被反序列化,部分的黑名单类如下:
- org.apache.commons.collections.functors.InvokerTransformer
- org.apache.commons.collections.functors.InstantiateTransformer
- org.apache.commons.collections4.functors.InvokerTransformer
- org.apache.commons.collections4.functors.InstantiateTransformer
- org.codehaus.groovy.runtime.ConvertedClosure
- org.codehaus.groovy.runtime.MethodClosure
- org.springframework.beans.factory.ObjectFactory
- com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
- org.apache.commons.fileupload
- org.apache.commons.beanutils
- …
安全编码建议
- 更新commons-collections、commons-io等第三方库版本;
- 业务需要使用反序列化时,尽量避免反序列化数据可被用户控制,如无法避免建议尽量使用白名单校验的修复方式;
相关文章:

应用安全:JAVA反序列化漏洞之殇
应用安全:JAVA反序列化漏洞之殇 概述 序列化是让Java对象脱离Java运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化存储。Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的 wri…...

基于以太坊的智能合约开发Solidity(函数继承篇)
参考教程:【实战篇】1、函数重载_哔哩哔哩_bilibili 1、函数重载: pragma solidity ^0.5.17;contract overLoadTest {//不带参数function test() public{}//带一个参数function test(address account) public{}//参数类型不同,虽然uint160可…...

【论文极速读】LVM,视觉大模型的GPT时刻?
【论文极速读】LVM,视觉大模型的GPT时刻? FesianXu 20231210 at Baidu Search Team 前言 这一周,LVM在arxiv上刚挂出不久,就被众多自媒体宣传为『视觉大模型的GPT时刻』,笔者抱着强烈的好奇心,在繁忙工作之…...

TS基础语法
前言: 因为在写前端的时候,发现很多UI组件的语法都已经开始使用TS语法,不学习TS根本看不到懂,所以简单的学一下TS语法。为了看UI组件的简单代码,不至于一脸懵。 一、安装node 对于windows来讲,node版本高…...

【基于NLP的微博情感分析:从数据爬取到情感洞察】
基于NLP的微博情感分析:从数据爬取到情感洞察 背景数据集技术选型功能实现创新点 今天我将分享一个基于NLP的微博情感分析项目,通过Python技术、NLP模型和Flask框架,对微博数据进行清洗、分词、可视化,并利用NLP和贝叶斯进行情感分…...

Ubuntu 18.04使用Qemu和GDB搭建运行内核的环境
安装busybox 参考博客: 使用GDBQEMU调试Linux内核环境搭建 一文教你如何使用GDBQemu调试Linux内核 ubuntu22.04搭建qemu环境测试内核 交叉编译busybox 编译busybox出现Library m is needed, can’t exclude it (yet)的解释 S3C2440 制作最新busybox文件系统 https:…...

GEE——利用Landsat系列数据集进行1984-2023EVI指数趋势分析
简介: 利用Landsat系列数据集进行1984-2023EVI指数趋势分析其主要目的是进行长时序的分析,这里我们选用EVI指数,然后进行了4个月的分析,查看其最后的线性趋势以及分布状况。 EVI指数: EVI指数(Enhanced Vegetation Index,增强型植被指数)是一种反映植被生长状态的遥…...

JAVA安全之Spring参数绑定漏洞CVE-2022-22965
前言 在介绍这个漏洞前,介绍下在spring下的参数绑定 在Spring框架中,参数绑定是一种常见的操作,用于将HTTP请求的参数值绑定到Controller方法的参数上。下面是一些示例,展示了如何在Spring中进行参数绑定: 示例1&am…...

辨析旅行商问题(TSP)与车辆路径问题(VRP)
目录 前言旅行商问题 (TSP)问题介绍数学模型符号定义问题输入约束条件目标函数问题输出 解的空间解空间大小计算解释 车辆路径问题 (VRP)问题介绍TSP到VRP的过渡数学模型符号定义问题输入约束条件优化目标问题输出 解空间特殊情况一般情况 TSP 与 VRP 对比 前言 计划是通过本文…...

2024年JAVA招聘行情如何?
大家都在说Java求职不好找,是真的吗?我们来看看数据。 数据支持:根据TIOBE 5月份的编程语言排行榜,Java仍然是前三名之一。这意味着,Java在开发领域仍然占据重要地位。 而在中国的IT市场中,Java仍然是主要…...

【合集】SpringBoot——Spring,SpringBoot,SpringCloud相关的博客文章合集
前言 本篇博客是spring相关的博客文章合集,内容涵盖Spring,SpringBoot,SpringCloud相关的知识,包括了基础的内容,比如核心容器,springMVC,Data Access;也包括Spring进阶的相关知识&…...

yolov5 获取漏检图片脚本
yolov5 获取漏检图片脚本 获取样本分数在0.05到0.38直接的样本。 # YOLOv5 by Ultralytics, GPL-3.0 licenseimport argparse import json import os import sys import time from pathlib import Pathimport cv2 import numpy as np import torch import torch.backends.cud…...

Unity之OpenXR+XR Interaction Toolkit接入微软VR设备Windows Mixed Reality
前言 Windows Mixed Reality 是 Microsoft 用于增强和虚拟现实体验的VR设备,如下图所示: 在国内,它的使用率很低,一把都是国外使用,所以适配起来是相当费劲。 这台VR设备只能用于串流Windows,启动后,会自动连接Window的Mixed Reality程序,然后打开微软的增强现实门户…...

【小聆送书第二期】人工智能时代AIGC重塑教育
🌈个人主页:聆风吟 🔥系列专栏:网络奇遇记、数据结构 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 📋正文📝活动参与规则 参与活动方式文末详见。 📋正文 AI正迅猛地…...

中国移动公网IP申请过程
一、动机 由于从事互联网行业10年,一直从事移动端(前端)开发工作,未曾深入了解过后端技术,以至于工作10年也不算进入互联网的门。 所以准备在自己家用设备上搭建各种场景的服务器(云服务对个人来说成本偏…...

动态获取绝对路径
在Python中,可以使用 os模块 来获取当前工作目录的路径,并使用 os.path.join()函数 将相对路径与当前工作目录结合起来,形成一个动态获取的绝对路径 以下是一个简单的例子: import os# 获取当前工作目录的路径 current_director…...

pytorch中的归一化:BatchNorm、LayerNorm 和 GroupNorm
1 归一化概述 训练深度神经网络是一项具有挑战性的任务。 多年来,研究人员提出了不同的方法来加速和稳定学习过程。 归一化是一种被证明在这方面非常有效的技术。 1.1 为什么要归一化 数据的归一化操作是数据处理的一项基础性工作,在一些实际问题中&am…...

RocketMq源码分析(九)--顺序消息
文章目录 一、顺序消息二、顺序消息消费过程1、消息队列负载2、消息拉取3、消息消费4、消息进度存储 三、总结 一、顺序消息 RocketMq在同一个队列中可以保证消息被顺序消费,所以如果要做到消息顺序消费,可以将消费主题(topic)设置…...

Windows下nginx的启动,重启,关闭等功能bat脚本
echo off rem 提供Windows下nginx的启动,重启,关闭功能echo begincls ::ngxin 所在的盘符 set NGINX_PATHG:::nginx 所在目录 set NGINX_DIRG:\projects\nginx-1.24.0\ color 0a TITLE Nginx 管理程序增强版CLSecho. echo. ** Nginx 管理程序 *** echo.…...

Python 字典:dic = {} 和 dic = defaultdict(list)之间的区别
d defaultdict(list) 和 d {} 在Python中代表了两种不同类型的字典初始化方式,它们之间有几个关键的区别: 1、类型 d defaultdict(list):这里使用的是 collections 模块中的 defaultdict 类。它是一个字典的子类,提供了一个默…...

绘图 Seaborn 10个示例
绘图 Seaborn 是什么安装使用显示中文及负号散点图箱线图小提琴图堆叠柱状图分面绘图分类散点图热力图成对关系图线图直方图 是什么 Seaborn 是一个Python数据可视化库,它基于Matplotlib。Seaborn提供了高级的绘图接口,可以用来绘制各种统计图形…...

airserver mac 7.27官方破解版2024最新安装激活图文教程
airserver mac 7.27官方破解版是一款好用的airplay投屏工具,可以轻松将ios荧幕镜像(airplay)至mac上,在mac平台上实现视频、音频、幻灯片等文件资源的接收及投放演示操作,解决iphone或ipad的屏幕录像问题,满…...

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《考虑移动式储能调度的配电网灾后多源协同孤岛运行策略》
这篇文章的标题表明研究的主题是在配电网发生灾害后,采用一种策略来实现多源协同孤岛运行,并在这个过程中特别考虑了移动式储能的调度。 让我们逐步解读标题的关键词: 考虑移动式储能调度: 文章关注的焦点之一是移动式储能系统的…...

Spring Boot 优雅地处理重复请求
前 言 对于一些用户请求,在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些是涉及写入操作的,一旦重复了,可能会导致很严重的后果,例如交易的接口如果重复请求可能会重复下单。 重复的场…...

TailwindCSS 多主题色配置
TailwindCSS 多主题色配置 现在大多数网站都支持主题色变换,比如切换深色模式。那么我们该如何进行主题色配置呢? tailwind dark tailwind 包含一个 dark变体,当启用深色模式时,可以为网站设置不同样式 <div class"bg-whi…...

Vue3:表格单元格内容由:图标+具体内容 构成
一、背景 在Vue3项目中,想让单元格的内容是由 :图标具体内容组成的,类似以下效果: 二、图标 Element-Plus 可以在Element-Plus里面找是否有符合需求的图标iconfont 如果Element-Plus里面没有符合需求的,也可以在这…...

【项目日记(一)】高并发内存池项目介绍
💓博主CSDN主页:杭电码农-NEO💓 ⏩专栏分类:项目日记-高并发内存池⏪ 🚚代码仓库:NEO的学习日记🚚 🌹关注我🫵带你学习C 🔝🔝 项目日记 1. 前言2. 什么是高并发内存池…...

4-Docker命令之docker commit
1.docker commit介绍 docker commit命令是用于根据docker容器的改变创建一个新的docker镜像 2.docker commit用法 docker commit [参数] container [repository[:tag]] [rootcentos79 ~]# docker commit --helpUsage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG…...

RabbitMQ学习笔记10 综合实战 实现新商家规定时间内上架商品检查
配置文件: 记住添加这个。 加上这段代码,可以自动创建队列和交换机以及绑定关系。 我们看到了我们创建的死信交换机和普通队列。 我们可以看到我们队列下面绑定的交换机。 我们创建一个controller包进行测试: 启动: 过一段时间会变成死信队列…...

Project Euler 865 Triplicate Numbers(线性dp)
题目 能通过每次消除3个一样的数字,最终把数字消成空的数字是合法的, 求串长度不超过n的,没有前导0的数字中,合法的数字的个数 n10000,答案对998244353取模,只需要输出数字 思路来源 乱搞AC 题解 暴力…...