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语句是否使用+、%s或f-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)
反序列化
反序列化漏洞的核心是程序将不可信的序列化数据还原为对象时,未验证数据合法性,导致攻击者通过构造恶意序列化数据执行任意代码。常见场景:
pickle模块的不安全使用:pickle.loads()直接反序列化用户输入。PyYAML的不安全加载:yaml.load()默认支持执行构造函数(如!!python/object)。- 自定义反序列化逻辑:开发者自行实现的
__reduce__方法被利用
1、不安全模块:pickle、marshal、PyYAML等。
2、防御措施:优先使用安全格式如JSON(json.loads())代替pickle。
3、第三方库的反序列化操作危险库:PyYAML(默认Loader不安全)、dill、shelve等
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:如SafeLoader或FullLoader
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并用危险函数/库解析:lxml、xml.etree.ElementTree、defusedxml未安全配置
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(1)</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权限,管理员用户 才能DROP或ALTER数据库
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 请求中,Referer 和 Origin 是两个与请求来源相关的头部字段,但它们的用途、格式和安全特性有显著区别。以下是它们的核心差异:
1、定义与格式
| 字段 | 定义 | 格式示例 | 包含路径信息 |
|---|---|---|---|
| Referer | 表示当前请求的 来源页面完整 URL | https://example.com/page.html | ✅ 包含路径(如 /page.html) |
| Origin | 表示当前请求的 协议 + 域名 + 端口(不包含路径) | https://example.com:8080 | ❌ 不包含路径 |
2、主要用途
| 字段 | 应用场景 | 典型用例 |
|---|---|---|
| Referer | - 统计流量来源 - 防止图片盗链(Hotlinking) - 分析用户行为 | 用户从 pageA.html 点击链接跳转到 pageB.html,Referer 值为 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、正确的使用直白一点就是:使用”逗号”,而不是”百分号” stmt "SELECT * FROM table WHERE id?" connectio…...
springboot启动配置文件-bootstrap.yml常用基本配置
在Spring Boot应用程序中,bootstrap.yml文件通常用于配置应用程序的启动阶段。在这个文件中,你可以配置一些在应用程序启动之前需要加载的属性,例如外部配置源、加密属性等。以下是一些常用的基本配置项: 1. 外部配置源 1.1 配置…...
2月3日星期一今日早报简报微语报早读
2月3日星期一,农历正月初六,早报#微语早读。 1、多个景区发布公告:售票数量已达上限,请游客合理安排行程; 2、2025春节档总票房破70亿,《哪吒之魔童闹海》破31亿; 3、美宣布对中国商品加征10…...
如何确认Linux嵌入式系统的触摸屏对应的是哪个设备文件(/dev/input/event1)?如何查看系统中所有的输入设备?输入设备的设备文件有什么特点?
Linux嵌入式系统的输入设备的设备文件有什么特点? 在 Linux 中,所有的输入设备(如键盘、鼠标、触摸屏等)都会被内核识别为 输入事件设备,并在 /dev/input/ 目录下创建相应的 设备文件,通常是: …...
FFmpeg:多媒体处理的瑞士军刀
FFmpeg:多媒体处理的瑞士军刀 前言 FFmpeg 是一个功能强大且跨平台的开源多媒体框架,广泛应用于音视频处理领域。 它由多个库和工具组成,能够处理各种音视频格式,涵盖编码、解码、转码、流处理等多种操作。 无论是专业视频编辑…...
电控三周速成计划参考
第1周:基础搭建与GPIO控制 学习目标:建立开发环境,掌握最基础的硬件控制能力 每日学习(2-3小时): 环境搭建(2天) 安装Keil MDK-ARM STM32CubeMX使用CubeMX创建第一个工程…...
Ubuntu修改配置文件--编辑操作
例如。 1.打开 /etc/samba/smb.conf 该配置文件: sudo vi /etc/samba/smb.conf 2.当你运行sudo vi /etc/samba/smb.conf命令后,你需要按i键进入插入模式(Insert Mode)。这时,在屏幕底部你应该能看到“-- INSERT --”…...
2021版小程序开发5——小程序项目开发实践(1)
2021版小程序开发5——小程序项目开发实践(1) 学习笔记 2025 使用uni-app开发一个电商项目; Hbuidler 首选uni-app官方推荐工具:https://www.dcloud.io/hbuilderx.htmlhttps://dev.dcloud.net.cn/pages/app/list 微信小程序 管理后台:htt…...
二分/双指针/单调栈队列专题
1.4924. 矩阵 - AcWing题库 一开始打表找规律以为是右上角向左下角递增,但当n很大的时候就不对了,因此我们得去观察 i * i 100000 * (i - j) j * j i * j 这个式子,我们关心的是这个式子的单调性因此我们可以分别将i和j看作常数来对式子进行求导,可以得到 f(i) 2 * i 10…...
XCCL、NCCL、HCCL通信库
XCCL提供的基本能力 XCCL提供的基本能力 不同的XCCL 针对不同的网络拓扑,实现的是不同的优化算法的(不同CCL库最大的区别就是这) 不同CCL库还会根据自己的硬件、系统,在底层上面对一些相对应的改动; 但是对上的API接口…...
【Deep Seek本地化部署】模型实测:规划求解python代码
目录 前言 一、实测 1、整数规划问题 2、非线性规划问题 二、代码正确性验证 1、整数规划问题代码验证 2、非线性规划问题代码验证 三、结果正确性验证 1、整数规划问题结果正确性验证 2、非线性规划问题正确性验证 四、整数规划问题示例 后记 前言 模型ÿ…...
MySQL锁类型(详解)
锁的分类图,如下: 锁操作类型划分 读锁 : 也称为共享锁 、英文用S表示。针对同一份数据,多个事务的读操作可以同时进行而不会互相影响,相互不阻塞的。 写锁 : 也称为排他锁 、英文用X表示。当前写操作没有完成前,它会…...
搜索插入位置(35)
35. 搜索插入位置 - 力扣(LeetCode) 相关算法:二分查找最左侧和最右侧target的index-CSDN博客 class Solution { public:int searchInsert(vector<int>& nums, int target) {int left 0;int right nums.size() - 1;int ans nu…...
八. Spring Boot2 整合连接 Redis(超详细剖析)
八. Spring Boot2 整合连接 Redis(超详细剖析) 文章目录 八. Spring Boot2 整合连接 Redis(超详细剖析)2. 注意事项和细节3. 最后: 在 springboot 中 , 整合 redis 可以通过 RedisTemplate 完成对 redis 的操作, 包括设置数据/获取数据 比如添加和读取数据 具体整…...
VDSuit-Full惯性动捕设备:高效率、高品质动画制作的利器
惯性动捕设备作为动画制作领域的新兴技术,与传统的关键帧动画制作相比,可以大大的缩短制作周期为创作者们提供极大便利。传统方式下,动画师需要逐帧调整角色动作,耗时费力。而惯性动捕设备能实时捕捉演员的动作,几乎瞬…...
【环境搭建】1.1源码下载与同步
目录 写在前面 一,系统要求 二,安装depot_tools 三,获取代码 四,代码同步 五,代码结构 写在前面 当前的开发背景是基于Google的开源Chromium,来开发Android设备的浏览器方案。 一,系统要…...
开源智慧园区管理系统对比其他十种管理软件的优势与应用前景分析
内容概要 在当今数字化快速发展的时代,园区管理软件的选择显得尤为重要。而开源智慧园区管理系统凭借其独特的优势,逐渐成为用户的新宠。与传统管理软件相比,它不仅灵活性高,而且具有更强的可定制性,让各类园区&#…...
C语言可变参数
在C语言中,处理可变参数(Variable Arguments)主要依赖于 <stdarg.h> 头文件中的一组宏定义。 以下是详细讲解和示例: 声明可变参数函数:使用 ... 表示可变参数 访问参数:通过 va_list 类型和配套宏…...
(1)Linux高级命令简介
Linux高级命令简介 在安装好linux环境以后第一件事情就是去学习一些linux的基本指令,我在这里用的是CentOS7作演示。 首先在VirtualBox上装好Linux以后,启动我们的linux,输入账号密码以后学习第一个指令 简介 Linux高级命令简介ip addrtou…...
frida 入门
一直想学 frida 一直鸽,终于有 ctf 用到了,我测东西这么多 官方文档感觉写的依托,这 python rpc 直接拿来入门真的太有生活了 frida 是一个动态插桩 (dynamic instrumentation) 工具,提供了交互式 cli 界面来追踪函数行为。用人话…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...
ui框架-文件列表展示
ui框架-文件列表展示 介绍 UI框架的文件列表展示组件,可以展示文件夹,支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项,适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...
边缘计算网关提升水产养殖尾水处理的远程运维效率
一、项目背景 随着水产养殖行业的快速发展,养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下,而且难以实现精准监控和管理。为了提升尾水处理的效果和效率,同时降低人力成本,某大型水产养殖企业决定…...
