Flask-Uploads:如何按内容(不仅仅是扩展名)强制文件类型



我正在使用Flask-Uploads来处理Web应用程序中的图像上传。该网络应用程序仅接受JPEG图像,但似乎Flask上传仅通过检查文件扩展名来强制执行此操作。

例如,我可以通过将文件名从myfile.txt更改为myfile.jpg来轻松颠覆这一点,并且文本文件myfile.txt将被错误地接受为 JPEG 图像。

如何确保上传到我的 Web 应用的文件实际上是按内容(而不仅仅是按文件扩展名(的 JPEG 文件?

这是一个最小的实现(不包括模板(,演示了我正在尝试做的事情:

# __init__.py
from flask import Flask
from flask_uploads import UploadSet, configure_uploads, IMAGES
from config import Config
app = Flask(__name__)
app.config.from_object(Config)
photos = UploadSet("photos", IMAGES)
configure_uploads(app, photos)
from app import routes
# routes.py
import os
from flask import redirect, render_template, send_from_directory, url_for
from flask_uploads import UploadNotAllowed
from app import app, photos
from app.forms import PhotoForm

@app.route('/', methods=["GET", "POST"])
def index():
form = PhotoForm()
if form.validate_on_submit():
try:
filename = photos.save(form.photo.data)
return redirect(url_for("uploaded_file", filename=filename))
except UploadNotAllowed:
print("UploadNotAllowed!")
redirect(url_for("index"))
return render_template("index.html", form=form)

@app.route("/uploads/<filename>")
def uploaded_file(filename):
directory = os.path.join(os.getcwd(), app.config["UPLOADED_PHOTOS_DEST"])
return send_from_directory(directory, filename)
# forms.py
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired
from wtforms import SubmitField

class PhotoForm(FlaskForm):
photo = FileField(validators=[FileRequired()])
submit = SubmitField("Upload")
# config.py
import os

class Config(object):
SECRET_KEY = os.environ.get("SECRET_KEY")
UPLOADED_PHOTOS_DEST = "uploads"
UPLOADED_PHOTOS_DENY = ["bmp", "gif", "png", "svg"]

您可以导入UploadSet并 - 如文档字符串中所述 - 覆盖file_allowed方法,例如创建自己的类,从UploadSet继承。

然后,您可以选择几个 Python 库之一,这些库可以检测类型,例如 https://github.com/ahupp/python-magic

PS:自 2020 年 2 月以来,Flask-Uploads被破坏了,至少是 PyPi 包。 我创建了一个叉子,这是一个直接的替代品,可通过 https://pypi.org/project/Flask-Reuploaded/