如何使用Python Flask禁止指定目录下的脚本执行
上传脚本目录执行权限限制方案(Flask + Python 3实现)
核心防护逻辑
需要结合操作系统权限管控和Flask应用层校验两层防护,避免单一层面被绕过导致脚本被执行。
1. 操作系统层面基础权限配置
先从底层限制上传目录下所有文件的执行权限,Linux环境下直接执行如下命令:
# 替换为你实际的上传目录路径 UPLOAD_DIR="/opt/app/user_upload_scripts" # 所有子目录设置为755权限(仅所有者可修改,其余用户仅可进入读取) find $UPLOAD_DIR -type d -exec chmod 755 {} \; # 所有普通文件设置为644权限,完全移除所有执行位 find $UPLOAD_DIR -type f -exec chmod 644 {} \; # 目录所属用户修改为Flask进程的运行用户,禁止其他用户修改权限 chown -R flask_run_user:flask_run_group $UPLOAD_DIR
注意:禁止给上传目录下的任何普通文件设置
x执行位,哪怕是Flask进程所有者的执行权限也不需要开启。
2. Flask应用层上传时权限管控
所有文件上传落盘时直接指定权限,避免操作系统默认权限带执行位,示例代码如下:
import os from flask import Flask, request, abort app = Flask(__name__) # 上传目录不要放在Flask的static、templates等默认路由可访问的目录下 app.config["UPLOAD_FOLDER"] = "/opt/app/user_upload_scripts" # 按需配置允许的文件后缀,建议不要加入py、js、sh、php等可执行脚本后缀 ALLOWED_EXTENSIONS = {"txt", "json", "csv", "md"} def check_file_ext(filename: str) -> bool: return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS @app.route("/script/upload", methods=["POST"]) def upload_script(): if "upload_file" not in request.files: abort(400, description="未上传文件") file = request.files["upload_file"] if file.filename == "": abort(400, description="文件名为空") if not check_file_ext(file.filename): abort(400, description="不允许的文件类型") # 建议对上传文件重命名,去掉原始可执行后缀,比如将xxx.py改为xxx_py.txt,避免被解析为可执行文件 save_filename = os.path.basename(file.filename).replace(".", "_") + ".txt" save_path = os.path.join(app.config["UPLOAD_FOLDER"], save_filename) file.save(save_path) # 落盘后立刻修改文件权限,移除执行位 os.chmod(save_path, 0o644) return "文件上传成功", 200
3. 后续防护加固
- 不要使用
send_from_directory等Flask内置方法直接返回上传目录下的文件,避免服务端自动解析执行脚本文件,所有文件读取需求都通过接口读取文件内容后返回。 - 可添加定时任务定期重置上传目录权限,防止遗漏的可执行权限残留,可通过APScheduler实现定时扫描:
from apscheduler.schedulers.background import BackgroundScheduler def reset_upload_permission(): upload_dir = app.config["UPLOAD_FOLDER"] for root, dirs, files in os.walk(upload_dir): # 重置目录权限 for d in dirs: os.chmod(os.path.join(root, d), 0o755) # 重置所有普通文件权限 for f in files: os.chmod(os.path.join(root, f), 0o644) # 服务启动时开启定时任务,每小时扫描一次 scheduler = BackgroundScheduler() scheduler.add_job(reset_upload_permission, "cron", hour="*") scheduler.start()
内容的提问来源于stack exchange,提问作者user16421569
相关产品推荐
相关产品推荐

