首页 > 解决方案 > 当默认加载器已经变得更安全时,为什么 PyYAML 5.1 会引发 YAMLLoadWarning?

问题描述

这是我的代码:

import yaml
yaml.load('foo')

此代码会导致 PyYAML (5.1) 出现以下警告。

$ pip install pyyaml
$ python3 foo.py
foo.py:2: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  yaml.load('foo')

所以我访问了https://msg.pyyaml.org/load以查看这是关于什么的,但我不明白需要这个警告。

首先,文档说,

UnsafeLoader(也要求Loader向后兼容)

可以很容易地被不受信任的数据输入利用的原始加载程序代码。

好吧,这是有道理的。在早期版本中,原始加载程序是不安全的。此外,它说,

FullLoader

加载完整的 YAML 语言。避免任意代码执行。这是当前(PyYAML 5.1)由yaml.load(input)(发出警告后)调用的默认加载程序。

所以当前版本使用FullLoader的是不是不安全的。这在文件中再次得到确认。

通过默认加载​​器 ( )禁止执行任意函数,加载函数也变得更加安全。FullLoader

如果当前使用的版本FullLoader不是不安全的,那我们为什么还需要YAMLLoadWarning呢?

标签: angularpython-3.xsecurityyamlwarnings

解决方案


我认为这个警告更像是一个通知和指导,让用户知道未来 PyYAML 的最佳实践是什么。回想一下:显式优于隐式。


在 5.1 版本之前(例如4.1),yaml.loadapi 使用Loader=Loader默认:

def load(stream, Loader=Loader):
    """
    Parse the first YAML document in a stream
    and produce the corresponding Python object.
    """
    loader = Loader(stream)
    try:
        return loader.get_single_data()
    finally:
        loader.dispose()

def safe_load(stream):
    """
    Parse the first YAML document in a stream
    and produce the corresponding Python object.
    Resolve only basic YAML tags.
    """
    return load(stream, SafeLoader)

那时,Loader只有三种可用的选择:limitedBaseLoaderSafeLoaderunsafe Loader。虽然默认的是不安全的,就像我们从文档中读到的一样:

PyYAML 的load功能自 2006 年 5 月首次发布以来一直是不安全的。它一直以粗体显示:PyYAMLDocumentation。PyYAML 一直提供一个safe_load可以加载 YAML 子集而不被利用的函数。

但是仍然有很多资源和教程更喜欢yaml.load(f)直接使用,因此用户(尤其是新用户)正在隐式选择默认的 Loader 类。


从 PyYAML 版本5.1开始,yaml.loadapi 被更改为更明确

def load(stream, Loader=None):
    """
    Parse the first YAML document in a stream
    and produce the corresponding Python object.
    """
    if Loader is None:
        load_warning('load')
        Loader = FullLoader

    loader = Loader(stream)
    try:
        return loader.get_single_data()
    finally:
        loader.dispose()

def safe_load(stream):
    """
    Parse the first YAML document in a stream
    and produce the corresponding Python object.
    Resolve only basic YAML tags. This is known
    to be safe for untrusted input.
    """
    return load(stream, SafeLoader)

并且一个新FullLoader的被添加到Loader中。作为用户,我们还应该了解这些变化并yaml.load明确地使用:

  • yaml.load(stream, yaml.SafeLoader)

    推荐用于不受信任的输入。限制:加载 YAML 语言的子集。

  • yaml.load(stream, yaml.FullLoader)

    获得更可信的输入。还有一点限制:避免任意代码执行。

  • yaml.load(stream, yaml.Loader)UnsafeLoader与 相同Loader

    不安全。却拥有十足的实力。


推荐阅读