Flask文件处理:Werkzeug Vs Flask上传



我正试图决定如何在我的flask应用程序上实现图像上传功能。我目前正在使用Flask Uploads来完成这项工作,它似乎运行得很好。然而,我不知道它是否非常安全,这可能是一个巨大的问题,因为涉及到文件上传。Flask Uploads并没有真正提供关于其服务实现的详细信息,所以我没有通过查看文档获得任何见解。然而,我看到Flask的官方文档中包含了一个使用Werkzeug上传文件的示例,该示例似乎有一些用于文件安全的额外方法。我似乎在网上找不到任何能说明哪一个更安全的东西。有没有人在这里有更多的网络安全经验,曾经检查过其中一个或两个替代方案,并对这个问题得出了明确的结论?

Flask Uploads实际上是使用Flask文档中的文件上传处理模式。它使用werkzeug.secure_filename,如果出于某种原因,您使用的是Flask 0.5或更早版本,它提供了一种设置MAX_CONTENT_LENGTH的方法,并且它提供了基于扩展名验证文件的方法。

事实上,Flask的文档实际上明确建议使用Flask Uploads:

因为在所有处理上传的应用程序中,文件上传的常见模式几乎没有变化,所以有一个名为Flask uploads的Flask扩展,它实现了一个完整的上传机制,扩展名包括白名单和黑名单等。

UTF-8支持

def secure_filename(filename):
    if isinstance(filename, text_type):
        from unicodedata import normalize
        filename = normalize('NFKD', filename).encode('utf-8', 'ignore')
        if not PY2:
            filename = filename.decode('utf-8')
    for sep in os.path.sep, os.path.altsep:
        if sep:
            filename = filename.replace(sep, ' ')
    filename = str(_filename_gbk_strip_re.sub('', '_'.join(
        filename.split()))).strip('._')
    if os.name == 'nt' and filename and 
       filename.split('.')[0].upper() in _windows_device_files:
        filename = '_' + filename
    return filename

解释

因此,secure_filename只支持ASCII,根据Docs的说法,建议的原因是为了最大限度地提高可移植性,这意味着如果文件名包含日语字符,它会返回一个空文件名,在这种情况下,从上面的函数派生的以下代码可能会有所帮助。

文件:https://werkzeug.palletsprojects.com/en/2.2.x/utils/

原始函数

def secure_filename(filename: str) -> str:
    r"""Pass it a filename and it will return a secure version of it.  This
    filename can then safely be stored on a regular file system and passed
    to :func:`os.path.join`.  The filename returned is an ASCII only string
    for maximum portability.
    On windows systems the function also makes sure that the file is not
    named after one of the special device files.
    >>> secure_filename("My cool movie.mov")
    'My_cool_movie.mov'
    >>> secure_filename("../../../etc/passwd")
    'etc_passwd'
    >>> secure_filename('i contain cool xfcmlxe4uts.txt')
    'i_contain_cool_umlauts.txt'
    The function might return an empty filename.  It's your responsibility
    to ensure that the filename is unique and that you abort or
    generate a random filename if the function returned an empty one.
    .. versionadded:: 0.5
    :param filename: the filename to secure
    """
    filename = unicodedata.normalize("NFKD", filename)
    filename = filename.encode("ascii", "ignore").decode("ascii")
    for sep in os.sep, os.path.altsep:
        if sep:
            filename = filename.replace(sep, " ")
    filename = str(_filename_ascii_strip_re.sub("", "_".join(filename.split()))).strip(
        "._"
    )
    # on nt a couple of special files are present in each folder.  We
    # have to ensure that the target file is not such a filename.  In
    # this case we prepend an underline
    if (
        os.name == "nt"
        and filename
        and filename.split(".")[0].upper() in _windows_device_files
    ):
        filename = f"_{filename}"
    return filename

我也建议查看Flask Uploads,因为如上所述,它遵循了werkzeug中secure_filename函数中提供的相同模式。我添加了UTF-8支持,指出了您可能面临的问题和源代码,这样您就可以看到werkzeug是如何提供安全文件名的。

最新更新