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

Flask代码审计实战

文章目录

    • Flask代码审计
      • SQL注入
      • 命令/代码执行
      • 反序列化
      • 文件操作
      • XXE
      • SSRF
      • XSS
      • 其他
    • 审计实战
    • 后记
    • reference

Flask代码审计

SQL注入

1、正确的使用直白一点就是:使用”逗号”,而不是”百分号”

stmt = "SELECT * FROM table WHERE id=?"
connection.execute(stmt, (value,))
#或者
cursor.execute("SELECT * FROM users WHERE name = ?", (username,))

2、检查所有SQL语句是否使用+%sf-string直接拼接用户输入

"SELECT * FROM table WHERE id=" + value
"SELECT * FROM table WHERE id=%s" % value
"SELECT * FROM table WHERE id={0}".format(value)

3、SQLAlchemy的text()是否进行参数化

from sqlalchemy import text
# 错误用法
stmt = text(f"SELECT * FROM users WHERE name = '{username}'")
# 正确用法
stmt = text("SELECT * FROM users WHERE name = :username").bindparams(username=username)
#或
query = "SELECT * FROM articles WHERE title LIKE :keyword"
result = db.session.execute(query, {"keyword": f"%{keyword}%"})

4、ORM安全使用:优先使用ORM方法

# SQLAlchemy ORM
User.query.filter_by(username=username).first()

命令/代码执行

1、危险函数popen、system、commands、subprocess、exec、eval

import subprocess@app.route('/ping')
def ping():ip = request.args.get('ip')result = subprocess.run(["ping", "-c", "1", ip], capture_output=True, text=True)return f"<pre>{result.stdout}</pre>"
#subprocess.run() 绑定参数,不会执行恶意命令。

2、SSTI

render_template_string

3、第三方库风险

import yaml
# 漏洞示例:使用默认Loader
data = yaml.load(user_input, Loader=yaml.Loader)  # 可触发任意代码执行

4、反序列化漏洞:pickle、marshal、PyYAML

import pickle
# 漏洞示例:反序列化用户可控数据
data = request.get_data()
obj = pickle.loads(data)  # 攻击者可构造恶意序列化对象(如反弹Shell)

反序列化

反序列化漏洞的核心是程序将不可信的序列化数据还原为对象时,未验证数据合法性,导致攻击者通过构造恶意序列化数据执行任意代码。常见场景:

  1. pickle模块的不安全使用pickle.loads()直接反序列化用户输入。
  2. PyYAML的不安全加载yaml.load()默认支持执行构造函数(如!!python/object)。
  3. 自定义反序列化逻辑:开发者自行实现的__reduce__方法被利用

1、不安全模块:picklemarshalPyYAML等。

2、防御措施:优先使用安全格式如JSON(json.loads())代替pickle

3、第三方库的反序列化操作危险库:PyYAML(默认Loader不安全)、dillshelve

4、安全使用pickle:仅反序列化可信数据确保序列化数据来源可信。签名验证对序列化数据签名,防止篡改。

import hmac, pickle
key = b'secret_key'
data = request.get_data()
# 验证HMAC签名
if not hmac.compare_digest(hmac.new(key, data).digest(), request.headers.get('Signature')):abort(403)
obj = pickle.loads(data)

5、安全使用PyYAML,强制使用安全Loader:如SafeLoaderFullLoader

import yaml
data = yaml.load(user_input, Loader=yaml.SafeLoader)  # 禁用构造函数

文件操作

1、关键函数

file()、file.save()、open()、codecs.open()

2、安全文件上传(白名单限制文件类型、重命名上传文件、magic验证文件内容)

ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg'}
def allowed_file(filename):return '.' in filename and \filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONSif file and allowed_file(file.filename):file.save("safe_path")import uuid
secure_name = str(uuid.uuid4()) + ".png"  # 生成随机文件名或通过secure_filename()
file.save(f"/uploads/{secure_name}")import magic
mime = magic.from_buffer(file.read(1024), mime=True)
if mime not in ['image/png', 'image/jpeg', 'image/gif']:abort(400, "Invalid file type")

3、防止路径遍历

from werkzeug.utils import secure_filename
import osfilename = secure_filename(request.form['filename'])  # 过滤特殊字符
base_dir = os.path.abspath("/var/data")
target_path = os.path.join(base_dir, filename)# 确保目标路径在base_dir下
if not os.path.commonprefix([base_dir, target_path]) == base_dir:abort(403, "Invalid path")

4、安全文件下载:映射文件名到安全ID,不直接暴露文件路径

# 数据库存储文件ID与真实路径的映射
@app.route('/download/<file_id>')
def download(file_id):file_path = db.get_file_path(file_id)  # 从数据库查询安全路径return send_file(file_path)

XXE

1、直接解析用户XML并用危险函数/库解析:lxmlxml.etree.ElementTreedefusedxml未安全配置

xml_data='''<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///c:/cc.txt">]>
<data>&xxe;</data>'''
from lxml import etree# 漏洞示例:直接解析用户输入
root = etree.fromstring(xml_data)  # 允许解析外部实体
print(root.text)

2、禁用外部实体解析、输入过滤、使用JSON替代XML

from defusedxml.ElementTree import parse
tree = parse(xml_file)  # 默认禁用外部实体from lxml import etree
parser = etree.XMLParser(resolve_entities=False)  # 禁用实体解析
root = etree.fromstring(xml_data, parser=parser)if re.search(r"<!ENTITY|SYSTEM|PUBLIC", xml_data, re.IGNORECASE):abort(400, "Invalid XML")

SSRF

1、直接请求、间接URL拼接用户提供的URL(urllib、requests等库)

# 漏洞示例:直接请求用户输入URL
url = request.form['url']
response = requests.get(url)  # 输入"file:///etc/passwd"可能读取文件(取决于库支持)# 漏洞示例:拼接用户输入到内部API
user_id = request.args.get('id')
internal_url = f"http://internal-api:8080/user/{user_id}"
requests.get(internal_url)  # 输入"id@evil.com"可能绕过校验
# requests.get()、urllib.request.urlopen()

2、名单校验域名/IP、限制协议类型、防止DNS重绑定攻击

ALLOWED_DOMAINS = {'example.com', 'cdn.example.net'}
from urllib.parse import urlparse
def is_allowed_url(url):parsed = urlparse(url)if parsed.hostname in ALLOWED_DOMAINS:return Truereturn False
if not is_allowed_url(url):abort(400, "Invalid URL")parsed = urlparse(url)
if parsed.scheme not in ['http', 'https']:abort(400, "Unsupported protocol")import socket
from urllib.parse import urlparse
parsed = urlparse(url)
hostname = parsed.hostname
# 解析DNS并验证IP是否合法
resolved_ip = socket.gethostbyname(hostname)
if resolved_ip in ['127.0.0.1', '169.254.169.254']:abort(403, "Forbidden IP")

XSS

1、直接渲染未转义的用户输入(|safe过滤器或Markup类或render_template_string或直接return输入)

from flask import Markup
user_input = request.args.get('q')
return render_template('search.html', result=Markup(user_input))<script>var userData = "{{ search_query|safe }}";  // 输入"; alert(1);//
</script>

2、payload

<svg><script>alert&#40;1&#41;</script></svg>  <!-- HTML实体编码绕过 -->
<script>alert(1)</script>
<img src=x onerror=alert(1)>
<img/src='1'/onerror=alert(0)>

3、使用 escape() 过滤用户输入,使用render_template渲染,设置 CSP(内容安全策略)

from markupsafe import escape@app.route('/comment', methods=['POST'])
def comment():username = escape(request.args.get('username')return render_template('profile.html', username=username)

4、文件上传

攻击者上传恶意 xss.svg

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"><circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" /><script>alert(1)</script>
</svg>

解决方案:禁止上传 SVG、HTML 文件或者对于所有用户上传的文件,使用 Content-Disposition: attachment,防止直接在浏览器解析

return send_from_directory(UPLOAD_FOLDER, filename, as_attachment=True)

其他

CSRF

from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)

权限校验

from flask_login import current_user
user = User.query.get(user_id)
if user.id != current_user.id:abort(403)

逻辑漏洞

# 漏洞示例:未加锁的余额扣减导致并发
user.balance -= amount
db.session.commit()  # 并发请求可能导致余额为负

组件漏洞

pip install safety
safety scan
safety system-scan
safety scan --apply-fixes

cors

# Flask-CORS 示例
from flask_cors import CORS
CORS(app, origins=["https://www.attacker.com"], supports_credentials=True)
Origin: http://www.attacker.com
#返回如下
Access-Control-Allow-Origin: https://www.attacker.com
Access-Control-Allow-Credentials: true
#或者如下
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
配置风险等级说明
Access-Control-Allow-Origin: * + Credentials: true安全(但错误)浏览器强制阻断请求
Access-Control-Allow-Origin: 任意值 + Credentials: true高危数据可被攻击者窃取
Access-Control-Allow-Origin: null + Credentials: true高危特殊场景下可绕过同源策略

修复核心:不要未经校验将客户端提供的 Origin 直接返回*,且携带凭证时禁止使用通配符 *null

key环境变量

import os
app.secret_key = os.getenv("SECRET_KEY", "fallback_secret")

最小权限原则

普通用户 只授予 SELECT, INSERT, UPDATE 权限,管理员用户 才能 DROPALTER 数据库

CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'strongpassword';
GRANT SELECT, INSERT, UPDATE ON mydb.* TO 'appuser'@'localhost';
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'adminpassword';
GRANT ALL PRIVILEGES ON mydb.* TO 'admin'@'localhost';

缓存安全

from flask import Flask, request, jsonify
from flask_caching import Cache
import redisapp = Flask(__name__)# 配置缓存(假设Redis在内网,已开启密码和TLS)
app.config['CACHE_TYPE'] = 'RedisCache'
app.config['CACHE_REDIS_HOST'] = '10.0.0.5'  # 内网IP
app.config['CACHE_REDIS_PORT'] = 6379
app.config['CACHE_REDIS_PASSWORD'] = 'strong_redis_password'
app.config['CACHE_KEY_PREFIX'] = 'myapp:'  # 使用命名空间隔离数据
app.config['CACHE_DEFAULT_TIMEOUT'] = 300cache = Cache(app)# 示例接口:存取用户数据(假设数据敏感,先加密后存储)
import hashlib
import base64def encrypt_data(data, key='secret_key'):# 这里仅示例使用简单的哈希加盐方式(实际请使用更安全的加密方法)return base64.b64encode(hashlib.sha256((data + key).encode()).digest()).decode()def decrypt_data(data, key='secret_key'):# 加密后无法直接解密,此处仅为示例return data@app.route('/store', methods=['POST'])
def store():username = request.form.get('username')secret_info = request.form.get('secret_info')if not username or not secret_info:return jsonify({'error': 'Missing parameters'}), 400# 加密敏感数据encrypted = encrypt_data(secret_info)cache_key = f"user:{username}:info"cache.set(cache_key, encrypted)return jsonify({'message': 'Stored securely'}), 200@app.route('/retrieve', methods=['GET'])
def retrieve():username = request.args.get('username')if not username:return jsonify({'error': 'Missing username'}), 400cache_key = f"user:{username}:info"encrypted = cache.get(cache_key)if not encrypted:return jsonify({'error': 'No data found'}), 404# 此处调用解密(如果能解密的话)info = decrypt_data(encrypted)return jsonify({'username': username, 'secret_info': info}), 200if __name__ == '__main__':app.run(debug=False)

审计实战

目标为某flask的cms,查找|safe关键词发现在article.html中存在该关键词

    {% if render_recommendations is defined %}{{ render_recommendations()|safe }}{% endif %}

__init__.py中声明render_recommendations上下文,查看render_recommendations()函数

    def init_app(self, app):"""初始化插件"""super().init_app(app)# 注册模板函数def render_recommendations():"""渲染推荐模板"""template_path = os.path.join(os.path.dirname(__file__), 'templates', 'recommendations.html')if os.path.exists(template_path):with open(template_path, 'r', encoding='utf-8') as f:template = f.read()return Markup(render_template_string(template))return ''# 直接添加到 Jinja2 环境app.jinja_env.globals['render_recommendations'] = render_recommendations

这里Markup和|safe将recommendations.html内容添加到article.html,如下

<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm p-8 mt-12 mb-8"><h3 class="text-xl font-bold mb-8 text-gray-900 dark:text-white flex items-center"><svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>相关推荐</h3><div id="recommendations-container" class="mb-2"><!-- 推荐内容将通过 JS 动态加载 --></div>
</div><script src="{{ url_for('article_recommender_static', filename='js/recommendations.js') }}"></script>

js文件如下:

功能模块作用
EMPTY_STATE_HTML当无推荐文章时显示空状态
ERROR_STATE_HTML当加载失败时显示错误状态
renderArticleCard(article)生成文章卡片 HTML
renderTags(tags)渲染标签(最多 2 个)
loadRecommendations(articleId)请求并渲染推荐文章
DOMContentLoaded 事件页面加载后自动获取推荐文章
function renderArticleCard(article) {return `<a href="/article/${article.id}" class="group block bg-gray-50 dark:bg-gray-700 rounded-lg p-6 transition-all duration-200 hover:shadow-md hover:bg-gray-100 dark:hover:bg-gray-600"><div class="space-y-4"><h4 class="font-bold text-gray-900 dark:text-gray-100 group-hover:text-blue-600 dark:group-hover:text-blue-400 transition-colors duration-200 line-clamp-2">${article.title}</h4><p class="text-sm text-gray-600 dark:text-gray-300 line-clamp-2">${article.summary}</p><div class="flex items-center justify-between"><span class="text-sm text-gray-500 dark:text-gray-400">${article.category}</span><div class="flex flex-wrap gap-2">${renderTags(article.tags)}</div></div></div></a>`;
}

title、category、tags三处均存在存储型xss,提交恶意payload<img/src='1'/onerror=alert(0)>后,在其他文章的相关推荐功能处渲染js代码完成弹窗

在这里插入图片描述

后记

Referer /Origin

在 HTTP 请求中,RefererOrigin 是两个与请求来源相关的头部字段,但它们的用途、格式和安全特性有显著区别。以下是它们的核心差异:


1、定义与格式

字段定义格式示例包含路径信息
Referer表示当前请求的 来源页面完整 URLhttps://example.com/page.html✅ 包含路径(如 /page.html
Origin表示当前请求的 协议 + 域名 + 端口(不包含路径)https://example.com:8080❌ 不包含路径

2、主要用途

字段应用场景典型用例
Referer- 统计流量来源 - 防止图片盗链(Hotlinking) - 分析用户行为用户从 pageA.html 点击链接跳转到 pageB.htmlReferer 值为 pageA.html
Origin- CORS(跨域资源共享)安全机制 - 限制跨域请求来源浏览器发起跨域 AJAX 请求时,自动添加 Origin 头供服务器验证

3、发送条件

字段触发发送的请求类型浏览器行为
Referer- 页面跳转(如 点击) - 资源加载(如, ``) - 表单提交(GET/POST)默认发送,但可能被浏览器策略(如 Referrer-Policy)或用户设置阻止
Origin- 跨域 AJAX(fetch/XMLHttpRequest) - POST 请求(部分浏览器) - WebSocket 连接仅在跨域请求或特定方法(如 POST)时发送

事务执行失败

如果事务执行失败,数据库连接可能会卡住,影响其他查询。

try:db.session.add(new_user)db.session.commit()
except Exception as e:db.session.rollback()  # 事务回滚,防止数据库状态异常print(f"Error: {e}")

reference

https://mp.weixin.qq.com/s/y1ta34MzowUnOvFnShk2MQ
https://www.freebuf.com/news/168362.html
https://blog.hackall.cn/cvesubmit/614.html
https://www.freebuf.com/articles/web/404899.html
https://blog.neargle.com/2016/07/25/log-of-simple-code-review-about-python-base-webapp/
https://www.cnblogs.com/xiaozi/p/7268506.html

相关文章:

Flask代码审计实战

文章目录 Flask代码审计SQL注入命令/代码执行反序列化文件操作XXESSRFXSS其他 审计实战后记reference Flask代码审计 SQL注入 1、正确的使用直白一点就是&#xff1a;使用”逗号”&#xff0c;而不是”百分号” stmt "SELECT * FROM table WHERE id?" connectio…...

Unity 2D实战小游戏开发跳跳鸟 - 跳跳鸟碰撞障碍物逻辑

在有了之前创建的可移动障碍物之后,就可以开始进行跳跳鸟碰撞到障碍物后死亡的逻辑,死亡后会产生一个对应的效果。 跳跳鸟碰撞逻辑 创建Obstacle Tag 首先跳跳鸟在碰撞到障碍物时,我们需要判定碰撞到的是障碍物,可以给障碍物的Prefab预制体添加一个Tag为Obstacle,添加步…...

【玩转 Postman 接口测试与开发2_015】第12章:模拟服务器(Mock servers)在 Postman 中的创建与用法(含完整实测效果图)

《API Testing and Development with Postman》最新第二版封面 文章目录 第十二章 模拟服务器&#xff08;Mock servers&#xff09;在 Postman 中的创建与用法1 模拟服务器的概念2 模拟服务器的创建2.1 开启侧边栏2.2 模拟服务器的两种创建方式2.3 私有模拟器的 API 秘钥的用法…...

mysql操作语句与事务

数据库设计范式 数据库设计的三大范式 ‌第一范式&#xff08;1NF&#xff09;‌&#xff1a;要求数据库表的每一列都是不可分割的原子数据项&#xff0c;即列中的每个值都应该是单一的、不可分割的实体。例如&#xff0c;如果一个表中的“地址”列包含了省、市、区等多个信息…...

android Camera 的进化

引言 Android 的camera 发展经历了3个阶段 &#xff1a; camera1 -》camera2 -》cameraX。 正文 Camera1 Camera1 的开发中&#xff0c;打开相机&#xff0c;设置参数的过程是同步的&#xff0c;就跟用户实际使用camera的操作步骤一样。但是如果有耗时情况发生时&#xff0c;会…...

ASP.NET Core Filter

目录 什么是Filter&#xff1f; Exception Filter 实现 注意 ActionFilter 注意 案例&#xff1a;自动启用事务的筛选器 事务的使用 TransactionScopeFilter的使用 什么是Filter&#xff1f; 切面编程机制&#xff0c;在ASP.NET Core特定的位置执行我们自定义的代码。…...

Git 的起源与发展

序章&#xff1a;版本控制的前世今生 在软件开发的漫长旅程中&#xff0c;版本控制犹如一位忠诚的伙伴&#xff0c;始终陪伴着开发者们。它的存在&#xff0c;解决了软件开发过程中代码管理的诸多难题&#xff0c;让团队协作更加高效&#xff0c;代码的演进更加有序。 简单来…...

基于SpringBoot电脑组装系统平台系统功能实现五

一、前言介绍&#xff1a; 1.1 项目摘要 随着科技的进步&#xff0c;计算机硬件技术日新月异&#xff0c;包括处理器&#xff08;CPU&#xff09;、主板、内存、显卡等关键部件的性能不断提升&#xff0c;为电脑组装提供了更多的选择和可能性。不同的硬件组合可以构建出不同类…...

【智力测试——二分、前缀和、乘法逆元、组合计数】

题目 代码 #include <bits/stdc.h> using namespace std; using ll long long; const int mod 1e9 7; const int N 1e5 10; int r[N], c[N], f[2 * N]; int nr[N], nc[N], nn, nm; int cntr[N], cntc[N]; int n, m, t;void init(int n) {f[0] f[1] 1;for (int i …...

第 1 天:UE5 C++ 开发环境搭建,全流程指南

&#x1f3af; 目标&#xff1a;搭建 Unreal Engine 5&#xff08;UE5&#xff09;C 开发环境&#xff0c;配置 Visual Studio 并成功运行 C 代码&#xff01; 1️⃣ Unreal Engine 5 安装 &#x1f539; 下载与安装 Unreal Engine 5 步骤&#xff1a; 注册并安装 Epic Game…...

axios如何利用promise无痛刷新token

目录 需求 需求解析 实现思路 方法一&#xff1a; 方法二&#xff1a; 两种方法对比 实现 封装axios基本骨架 instance.interceptors.response.use拦截实现 问题和优化 如何防止多次刷新token 同时发起两个或以上的请求时&#xff0c;其他接口如何重试 最后完整代…...

玉米苗和杂草识别分割数据集labelme格式1997张3类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;1997 标注数量(json文件个数)&#xff1a;1997 标注类别数&#xff1a;3 标注类别名称:["corn","weed","Bean…...

【自学笔记】GitHub的重点知识点-持续更新

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 GitHub使用指南详细知识点一、GitHub基础与账户管理1. GitHub简介2. 创建与管理GitHub账户3. 创建与配置仓库&#xff08;Repository&#xff09; 二、Git基础与Git…...

string例题

一、字符串最后一个单词长度 题目解析&#xff1a;由题输入一段字符串或一句话找最后一个单词的长度&#xff0c;也就是找最后一个空格后的单词长度。1.既然有空格那用我们常规的cin就不行了&#xff0c;我们这里使用getline,2.读取空格既然是最后一个空格后的单词&#xff0c;…...

算法基础——一致性

引入 最早研究一致性的场景既不是大数据领域&#xff0c;也不是分布式系统&#xff0c;而是多路处理器。 可以将多路处理器理解为单机计算机系统内部的分布式场景&#xff0c;它有多个执行单元&#xff0c;每一个执行单元都有自己的存储(缓存)&#xff0c;一个执行单元修改了…...

【数据采集】案例01:基于Scrapy采集豆瓣电影Top250的详细数据

基于Scrapy采集豆瓣电影Top250的详细数据 Scrapy 官方文档:https://docs.scrapy.org/en/latest/豆瓣电影Top250官网:https://movie.douban.com/top250写在前面 实验目的:基于Scrapy框架采集豆瓣电影Top250的详细数据。 电脑系统:Windows 使用软件:PyCharm、Navicat Python…...

设计模式 - 行为模式_Template Method Pattern模板方法模式在数据处理中的应用

文章目录 概述1. 核心思想2. 结构3. 示例代码4. 优点5. 缺点6. 适用场景7. 案例&#xff1a;模板方法模式在数据处理中的应用案例背景UML搭建抽象基类 - 数据处理的 “总指挥”子类定制 - 适配不同供应商供应商 A 的数据处理器供应商 B 的数据处理器 在业务代码中整合运用 8. 总…...

Spring Boot框架下的单元测试

1. 什么是单元测试 1.1 基本定义 单元测试(Unit Test) 是对软件开发中最小可测单位&#xff08;例如一个方法或者一个类&#xff09;进行验证的一种测试方式。在 Java 后端的 Spring Boot 项目中&#xff0c;单元测试通常会借助 JUnit、Mockito 等框架对代码中核心逻辑进行快…...

git中文件的状态状态切换

在 Git 中&#xff0c;文件的状态是指文件相对于 Git 仓库的当前情况。以下是一些常见的文件状态及其含义&#xff1a; 未跟踪&#xff08;Untracked&#xff09;&#xff1a; 这是新创建的文件或从其他位置复制过来的文件&#xff0c;Git 还没有开始跟踪这些文件的更改。 这些…...

基于脉冲响应不变法的IIR滤波器设计与MATLAB实现

一、设计原理 脉冲响应不变法是一种将模拟滤波器转换为数字滤波器的经典方法。其核心思想是通过对模拟滤波器的冲激响应进行等间隔采样来获得数字滤波器的单位脉冲响应。 设计步骤&#xff1a; 确定数字滤波器性能指标 将数字指标转换为等效的模拟滤波器指标 设计对应的模拟…...

RabbitMQ快速上手及入门

概念 概念&#xff1a; publisher&#xff1a;生产者&#xff0c;也就是发送消息的一方 consumer&#xff1a;消费者&#xff0c;也就是消费消息的一方 queue&#xff1a;队列&#xff0c;存储消息。生产者投递的消息会暂存在消息队列中&#xff0c;等待消费者处理 exchang…...

自动化构建-make/Makefile 【Linux基础开发工具】

文章目录 一、背景二、Makefile编译过程三、变量四、变量赋值1、""是最普通的等号2、“:” 表示直接赋值3、“?” 表示如果该变量没有被赋值&#xff0c;4、""和写代码是一样的&#xff0c; 五、预定义变量六、函数**通配符** 七、伪目标 .PHONY八、其他常…...

计算机网络之计算机网络的分类

计算机网络可以根据不同的角度进行分类&#xff0c;以下是几种常见的分类方式&#xff1a; 1. 按照规模和范围&#xff1a; 局域网&#xff08;LAN&#xff0c;Local Area Network&#xff09;&#xff1a;覆盖较小范围&#xff08;例如一个建筑物或校园&#xff09;&#xf…...

MySQl的日期时间加

MySQL日期相关_mysql 日期加减-CSDN博客MySQL日期相关_mysql 日期加减-CSDN博客 raise notice 查询目标 site:% model:% date:% target:%,t_shipment_date.site,t_shipment_date.model,t_shipment_date.plant_date,v_date_shipment_qty_target;...

响应式编程与协程

响应式编程与协程的比较 响应式编程的弊端虚拟线程Java线程内核线程的局限性传统线程池的demo虚拟线程的demo 响应式编程的弊端 前面用了几篇文章介绍了响应式编程&#xff0c;它更多的使用少量线程实现线程间解耦和异步的作用&#xff0c;如线程的Reactor模型&#xff0c;主要…...

智能小区物业管理系统推动数字化转型与提升用户居住体验

内容概要 在当今快速发展的社会中&#xff0c;智能小区物业管理系统的出现正在改变传统的物业管理方式。这种系统不仅仅是一种工具&#xff0c;更是一种推动数字化转型的重要力量。它通过高效的技术手段&#xff0c;将物业管理与用户居住体验紧密结合&#xff0c;无疑为社区带…...

从Proxmox VE开始:安装与配置指南

前言 Proxmox Virtual Environment (Proxmox VE) 是一个开源的虚拟化平台&#xff0c;基于Debian Linux&#xff0c;支持KVM虚拟机和LXC容器。它提供了一个强大的Web管理界面&#xff0c;方便用户管理虚拟机、存储、网络等资源。Proxmox VE广泛应用于企业级虚拟化、云计算和开…...

【Docker项目实战】使用Docker部署MinIO对象存储(详细教程)

【Docker项目实战】使用Docker部署MinIO对象存储 前言一、 MinIO介绍1.1 MinIO简介1.2 主要特点1.3 主要使用场景二、本次实践规划2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本四、下载MinIO镜像五、…...

【C++】B2115 密码翻译

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目解析&#x1f4af;1. 老师的做法代码实现&#xff1a;思路解析&#xff1a; &#x1f4af;2. 我的做法代码实现&#xff1a;思路分析&#xff1a; &#x1f4af;3. 老师…...

02.04 数据类型

请写出以下几个数据的类型&#xff1a; 整数 a ----->int a的地址 ----->int* 存放a的数组b ----->int[] 存放a的地址的数组c ----->int*[] b的地址 ----->int* c的地址 ----->int** 指向printf函数的指针d ----->int (*)(const char*, ...) …...