Python Discord Bot使用yt-dlp下载MP3的路径遍历安全问题
基于yt-dlp的Discord音乐下载机器人安全优化方案
核心风险说明
仅靠restrictfilenames: True不足以完全规避路径遍历风险——yt-dlp返回的info['title']仍可能包含相对路径片段(如../),直接拼接路径会导致文件被写入非预期目录,引发安全问题。
具体优化措施
1. 利用yt-dlp内置路径生成逻辑(推荐)
放弃手动拼接路径,通过yt-dlp的outtmpl参数指定输出模板,确保文件始终落在目标下载目录:
import os import yt_dlp import discord ydl_opts = { 'format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '192', }], 'restrictfilenames': True, # 用os.path.join确保路径跨平台兼容,通过模板指定保存位置 'outtmpl': os.path.join(download_path, '%(title)s.%(ext)s'), 'noplaylist': True, } @client.command() async def dl(ctx, arg): with yt_dlp.YoutubeDL(ydl_opts) as ydl: # 启用download=True直接下载到指定路径 info = ydl.extract_info(arg, download=True) # 获取实际生成的MP3文件路径(处理转码后的扩展名变化) original_file = ydl.prepare_filename(info) mp3_file = original_file.rsplit('.', 1)[0] + '.mp3' await ctx.send("下载完成", file=discord.File(mp3_file))
2. 手动严格清理文件名
如果必须手动处理文件名,需彻底过滤路径相关字符并校验最终路径:
import os def sanitize_filename(name): # 移除所有路径分隔符和相对路径标记 name = name.replace('/', '').replace('\\', '') name = name.replace('../', '').replace('./', '') # 仅保留纯文件名,丢弃任何路径部分 return os.path.basename(name) @client.command() async def dl(ctx, arg): with yt_dlp.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(arg) safe_title = sanitize_filename(info['title']) target_path = os.path.join(download_path, f"{safe_title}.mp3") # 强制校验:确保生成的路径在目标目录范围内 abs_target = os.path.abspath(target_path) abs_download_dir = os.path.abspath(download_path) if not abs_target.startswith(abs_download_dir + os.sep): await ctx.send("文件名存在安全风险,取消下载") return await ctx.send("ok goude", file=discord.File(target_path))
3. 降低运行权限与目录限制
- 以非管理员用户身份运行机器人进程,限制恶意操作的影响范围
- 对下载目录设置最小权限:仅机器人进程拥有读写权限,禁止其他用户访问
4. 输入合法性校验
- 校验用户提供的链接格式,仅允许合法的YouTube链接(匹配
https://www.youtube.com/watch?v=或https://youtu.be/等格式) - 限制下载文件的最大大小,避免恶意占用服务器存储资源
关键原则
永远不要信任外部输入(包括yt-dlp返回的元数据),必须通过多层校验确保路径安全;优先依赖库内置的安全处理逻辑,减少手动拼接路径的错误。
内容的提问来源于stack exchange,提问作者Alexis Leclerc
相关产品推荐
相关产品推荐

