标准Flask项目模板(一键脚本)


flask secure_filename 安全命名

secure_filename() 在很多情况下非常有必要,尤其是在处理用户上传文件时。


💡 背景

当你让用户上传文件(比如 Flask 中的 request.files['file']), 用户的文件名可能包含各种危险或特殊内容,比如:

../../../etc/passwd
my file.png
script<script>.jpg

这些名字在操作系统、服务器、或 URL 中使用时可能导致问题,比如:

  • 路径穿越攻击(Path Traversal)
  • 特殊字符错误
  • 不同系统编码不兼容
  • 无法正确保存或访问文件

✅ Flask 的解决方法

Flask 提供了 werkzeug.utils.secure_filename 来自动清理文件名:

from werkzeug.utils import secure_filename

filename = secure_filename(uploaded_file.filename)
uploaded_file.save(f"./uploads/{filename}")

secure_filename("../../../etc/passwd") 👉 会变成

etc_passwd

secure_filename("my file.png") 👉 会变成

my_file.png

⚠️ 如果不用 secure_filename 会怎样?

假设你写:

f.save("./uploads/" + f.filename)

而用户上传的文件名是:

../../app.py

那你可能覆盖掉你自己的代码文件,甚至被攻击者写入恶意脚本。😱


💬 总结

场景是否建议用 secure_filename
用户上传文件✅ 必须用
你自己在代码里创建的文件❌ 不需要
文件名来自外部 API 或第三方输入✅ 建议用

改进 secure_filename,让中文保留

Werkzeug 的 secure_filename 默认只保留 ASCII 字母。 你可以写一个小函数,保留中文和常见字符:

import re

def safe_filename(filename):
    # 保留中文、英文、数字、下划线、点、横线
    return re.sub(r'[^0-9A-Za-z\u4e00-\u9fa5._-]', '_', filename)

然后替换原来的:

song_filename = safe_filename(song.filename)

这样:

“夏天的风(完整版).flac” → “夏天的风_完整版_.flac”

“My Song.mp3” → “My_Song.mp3”

会安全又美观 ✅