كيفية إلغاء تمييز كائن مع pyyaml ​​باستخدام safe_load؟

StackOverflow https://stackoverflow.com/questions/2627555

  •  26-09-2019
  •  | 
  •  

سؤال

وجود مقتطف مثل هذا:

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 يقول أنه ليس من الآمن الاتصال yaml.load مع أي بيانات تم استلامها من مصدر غير موثوق ؛ لذا ، ما الذي يجب علي تعديله إلى الفصل الخاص بي للاستخدام Safe_Load طريقة؟
هل هو ممكن؟

هل كانت مفيدة؟

المحلول

يبدو أن 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)

الميزة هنا هي أن لديك سيطرة مطلقة على كيفية تسلسل صفك (DE). هذا يعني أنك لن تحصل على رمز قابل للتنفيذ عشوائي عبر الشبكة وتشغيله. العيب هو أن لديك سيطرة مطلقة على كيفية تصنيف صفك (DE). هذا يعني أنه يجب عليك القيام بالكثير من العمل. ؛-)

نصائح أخرى

هناك طريقة أخرى. من مستندات Pyyaml:

يمكن تمييز كائن Python على أنه آمن وبالتالي يتم التعرف عليه بواسطة Yaml.Safe_Load. للقيام بذلك ، استمدها من yaml.yamlobject [...] وتعيين خاصية فئة yaml_loader بشكل صريح إلى yaml.safeloader.

يجب عليك أيضًا تعيين خاصية Yaml_Tag لجعلها تعمل.

يقوم Yamlobject ببعض السحر metaclass لجعل الكائن قابل للتحميل. لاحظ أنه إذا قمت بذلك ، فلن يتم تحميل الكائنات إلا عن طريق المحمل الآمن ، وليس مع 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 و Clutters صفك بسمات متعلقة بالتسلسل و metaclass.

إذا كان لديك العديد من العلامات ولا ترغب في إنشاء كائنات لها جميعًا ، أو في حالة عدم اهتمامك بالنوع الفعلي الذي تم إرجاعه ، فقط حول الوصول المنقط ، يمكنك التقاط جميع العلامات غير المحددة مع الكود التالي:

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) عليها لإنهاءها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top