如何使用 safe_load 使用 PyYAML 反序列化对象?

发布于 2024-08-28 06:51:02 字数 601 浏览 6 评论 0原文

有这样的片段:

import yaml
class User(object):
    def __init__(self, name, surname):
       self.name= name
       self.surname= surname

user = User('spam', 'eggs')
serialized_user = yaml.dump(user)
#Network
deserialized_user = yaml.load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

Yaml docs 表示调用 yaml.load< 并不安全/strong> 从不受信任的来源收到的任何数据;那么,我应该对我的 snippet\class 进行哪些修改才能使用 safe_load 方法?
是否可以?

Having a snippet like this:

import yaml
class User(object):
    def __init__(self, name, surname):
       self.name= name
       self.surname= surname

user = User('spam', 'eggs')
serialized_user = yaml.dump(user)
#Network
deserialized_user = yaml.load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

Yaml docs says that it is not safe to call yaml.load with any data received from an untrusted source; so, what should I modify to my snippet\class to use safe_load method?
Is it possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

〃安静 2024-09-04 06:51:02

还存在另一种方式。来自 PyYaml 文档:

Python 对象可以被标记为安全,从而被 yaml.safe_load 识别。为此,请从 yaml.YAMLObject [...] 派生它,并将其类属性 yaml_loader 显式设置为 yaml.SafeLoader。

您还必须设置 yaml_tag 属性才能使其正常工作。

YAMLObject 使用一些元类魔法来使对象可加载。请注意,如果这样做,对象将只能由安全加载器加载,而不能使用常规 yaml.load() 加载。

工作示例:

import yaml

class User(yaml.YAMLObject):
    yaml_loader = yaml.SafeLoader
    yaml_tag = u'!User'

    def __init__(self, name, surname):
       self.name= name
       self.surname= surname

user = User('spam', 'eggs')
serialized_user = yaml.dump(user)

#Network

deserialized_user = yaml.safe_load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

这个的优点是很容易做;缺点是它只能与 safe_load 一起使用,并且会使您的类与序列化相关的属性和元类变得混乱。

Another way exists. From the PyYaml docs:

A python object can be marked as safe and thus be recognized by yaml.safe_load. To do this, derive it from yaml.YAMLObject [...] and explicitly set its class property yaml_loader to yaml.SafeLoader.

You also have to set the yaml_tag property to make it work.

YAMLObject does some metaclass magic to make the object loadable. Note that if you do this, the objects will only be loadable by the safe loader, not with regular yaml.load().

Working example:

import yaml

class User(yaml.YAMLObject):
    yaml_loader = yaml.SafeLoader
    yaml_tag = u'!User'

    def __init__(self, name, surname):
       self.name= name
       self.surname= surname

user = User('spam', 'eggs')
serialized_user = yaml.dump(user)

#Network

deserialized_user = yaml.safe_load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

The advantage of this one is that it's prety easy to do; the disadvantages are that it only works with safe_load and clutters your class with serialization-related attributes and metaclass.

不必你懂 2024-09-04 06:51:02

根据定义,safe_load 似乎不允许您反序列化自己的类。如果您希望它安全,我会这样做:

import yaml
class User(object):
    def __init__(self, name, surname):
       self.name= name
       self.surname= surname

    def yaml(self):
       return yaml.dump(self.__dict__)

    @staticmethod
    def load(data):
       values = yaml.safe_load(data)
       return User(values["name"], values["surname"])

user = User('spam', 'eggs')
serialized_user = user.yaml()
print "serialized_user:  %s" % serialized_user.strip()

#Network
deserialized_user = User.load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

这里的优点是您可以绝对控制您的类的序列化(反)序列化方式。这意味着您不会通过网络获得随机可执行代码并运行它。缺点是您可以绝对控制您的类的序列化(反)序列化方式。这意味着你必须做更多的工作。 ;-)

It appears that safe_load, by definition, does not let you deserialize your own classes. If you want it to be safe, I'd do something like this:

import yaml
class User(object):
    def __init__(self, name, surname):
       self.name= name
       self.surname= surname

    def yaml(self):
       return yaml.dump(self.__dict__)

    @staticmethod
    def load(data):
       values = yaml.safe_load(data)
       return User(values["name"], values["surname"])

user = User('spam', 'eggs')
serialized_user = user.yaml()
print "serialized_user:  %s" % serialized_user.strip()

#Network
deserialized_user = User.load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

The advantage here is that you have absolute control over how your class is (de)serialized. That means that you won't get random executable code over the network and run it. The disadvantage is that you have absolute control over how your class is (de)serialized. That means you have to do a lot more work. ;-)

海风掠过北极光 2024-09-04 06:51:02

如果您有许多标签并且不想为所有标签创建对象,或者如果您不关心返回的实际类型,只关心点访问,则可以使用以下代码捕获所有未定义的标签

import yaml

class Blob(object):
    def update(self, kw):
        for k in kw:
            setattr(self, k, kw[k])

from yaml.constructor import SafeConstructor

def my_construct_undefined(self, node):
    data = Blob()
    yield data
    value = self.construct_mapping(node)
    data.update(value)

SafeConstructor.add_constructor(None, my_construct_undefined)


class User(object):
    def __init__(self, name, surname):
        self.name= name
        self.surname= surname

user = User('spam', 'eggs')
serialized_user = yaml.dump(user)
#Network
deserialized_user = yaml.safe_load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

:想知道为什么 my_construct_undefined 中间有一个 yield:它允许将对象实例化与其子对象的创建分开。一旦对象存在,就可以引用它(如果它有锚点),并且可以对子对象(或其子对象)进行引用。创建对象的实际机制首先创建它,然后对其执行 next(x) 来完成它。

If you have many tags and don't want to create objects for all of them, or in case you don't care about the actual type returned, only about dotted access, you catch all undefined tags with the following code:

import yaml

class Blob(object):
    def update(self, kw):
        for k in kw:
            setattr(self, k, kw[k])

from yaml.constructor import SafeConstructor

def my_construct_undefined(self, node):
    data = Blob()
    yield data
    value = self.construct_mapping(node)
    data.update(value)

SafeConstructor.add_constructor(None, my_construct_undefined)


class User(object):
    def __init__(self, name, surname):
        self.name= name
        self.surname= surname

user = User('spam', 'eggs')
serialized_user = yaml.dump(user)
#Network
deserialized_user = yaml.safe_load(serialized_user)
print "name: %s, sname: %s" % (deserialized_user.name, deserialized_user.surname)

In case you wonder why the my_construct_undefined has a yield in the middle: that allows for instantiating the object separately from creation of its children. Once the object exist it can be referred to in case it has an anchor and of the children (or their children) a reference. The actual mechanisme to create the object first creates it, then does a next(x) on it to finalize it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文