简体   繁体   English

将对象序列化为文件时的C#最佳实践

[英]C# best practice when serializing objects to file

I'm building a small app that needs to save an object to a file in order to save user data. 我正在构建一个小应用程序,需要将对象保存到文件中以保存用户数据。 I have two questions about my serialization to this file : 关于我对此文件的序列化,我有两个问题:

  1. The object I'm creating has some public properties and an event. 我正在创建的对象有一些公共属性和一个事件。 I added the [Serializable] attribute to my object, and then realized I can't serialize an object with an event in it. 我将[Serializable]属性添加到我的对象,然后意识到我不能序列化一个带有事件的对象。 I then discovered that I can just add an attribute above my event [field:NonSerialized] and it will work. 然后我发现我可以在我的事件[field:NonSerialized]之上添加一个属性,它会起作用。 Is this the best way to do this, or should I try to build my Serializable objects without any events inside ? 这是最好的方法吗,或者我应该尝试构建我的Serializable对象而没有任何事件?

  2. The object I'm serializing saves some user settings about the app. 我正在序列化的对象保存了一些关于应用程序的用户设置。 These settings aren't sensitive enough to go about encrypting them in the file, but i still don't want them to be tampered with manually without opening my application. 这些设置不够灵敏,无法在文件中加密它们,但我仍然不希望它们在不打开我的应用程序的情况下手动篡改。 When i serialize my object to a file using a plain BinaryFormatter object, via the Serialize() method, I see readable names of .net object types in the file i'm saving this to. 当我使用普通的BinaryFormatter对象将我的对象序列化为文件时,通过Serialize()方法,我在文件中看到.net对象类型的可读名称,我将其保存到。 Is there a way for someone to reverse engineer this and see what's being saved without using my program ? 有没有办法让某人对此进行逆向工程,看看在不使用我的程序的情况下保存了什么? Is there a way for someone to build a small application and find out how to DeSerialize the information in this file ? 有没有办法让某人建立一个小应用程序,并找出如何DeSerialize此文件中的信息? If so, how would i go about hiding the information in this file ? 如果是这样,我将如何隐藏此文件中的信息?

Are there any other tips/suggestions/best practices i should stick to when going about serializing an object to a file in this kind of scenario ? 在这种情况下,当将对象序列化为文件时,是否还有其他提示/建议/最佳实践?

Thanks in advance! 提前致谢!

If your object implements the ISerializable interface, you can control all the data that is stored/serialized yourself, and you can control the deserialization. 如果您的对象实现了ISerializable接口,您可以自己控制所有存储/序列化的数据,并且可以控制反序列化。

This is important if your project evolves in time. 如果您的项目及时发展,这一点非常重要。 Because you might drop some properties, add others, or change the behaviour. 因为您可能会删除某些属性,添加其他属性或更改行为。

I always add a version to the serialization bag. 我总是在序列化包中添加一个版本。 That way I know what was the version of the object when it was stored, and I therefor know how to deserialize it. 这样我知道对象存储时的版本是什么,因此我知道如何反序列化它。

[Serializable]
class Example : ISerializable {
   private static const int VERSION = 3;

   public Example(SerializationInfo info, StreamingContext context) {
      var version = info.GetInt32("Example_Version", VERSION);
      if (version == 0) {
         // Restore properties for version 0
      }
      if (version == 1) {
         // ....
      }
   }

   void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
       info.AddValue("Example_Version", VERSION);
       // Your data here
   }

}

And if you do not encrypt, it will be very easy to "read" your data. 如果您不加密,则可以非常轻松地“读取”您的数据。 Very easy meaning you might have to invest a couple of hours. 很容易意味着您可能需要投入几个小时。 If the data you store is worth a couple of days, this means it is easy, if it is only worth a couple of minutes it is hard. 如果您存储的数据值几天,这意味着它很容易,如果它只值几分钟很难。 If you get the point. 如果你明白了。

A very easy way to encrypt your data is using the Windows DPAPI through the ProtectedData class. 加密数据的一种非常简单的方法是通过ProtectedData类使用Windows DPAPI。

1: with BinaryFormatter, yes - you need NonSerialized for events (unless you implement ISerializable, but that adds lots of work); 1:使用BinaryFormatter,是的 - 你需要NonSerialized用于事件(除非你实现了ISerializable,但这增加了很多工作); however I'm pretty much on-record as saying that I simply wouldn't use BinaryFormatter here. 然而,我几乎记录在案,我不会在这里使用BinaryFormatter。 It is not very forgivig for a range of changes to your type. 对您的类型进行一系列更改并不是非常原谅。 I would use something less tied to the internals of your code; 我会使用与代码内部相关的东西; XmlSerializer; XmlSerializer的; DataContractSerializer, JavaScriptSerializer. DataContractSerializer,JavaScriptSerializer。 I can suggest binary alternatives too; 我也可以建议二元替代品; NetDataContractSerializer, protobuf-net (my own), etc. NetDataContractSerializer,protobuf-net(我自己的)等。

2: yes, with almost any implementation that doesnt involve proper encryption, if anyone cares they can reverse engineer and obtain the strings. 2:是的,几乎所有不涉及正确加密的实现,如果有人关心他们可以逆向工程并获得字符串。 So it depends how hidden it needs to be. 所以它取决于它需要隐藏的程度。 Simply running your existing serialization through GZipStream may be enough obfuscation for your needs, BUT this is just a mask against casual inspection. 简单地通过GZipStream运行现有的序列化可能足以满足您的需求,但这只是一个反对随意检查的掩码。 It will not deter anyone with a reason to look for the data. 它不会阻止任何人有理由寻找数据。

If the data needs to be secure, you'll need proper encryption using either a key the user enters at app startup, or something like a certificate securely stores against their user-profile. 如果数据需要是安全的,那么您需要使用用户在应用启动时输入的密钥进行适当的加密,或者根据用户配置文件安全存储证书。

  1. I would remove the events from the objects. 我会从对象中删除事件。 It's a little cleaner that way. 这样有点干净。

  2. Anything can be reverse engineered. 任何东西都可以逆向工程。 Just encrypt it when saving the file. 只需在保存文件时加密即可。 It's pretty easy to do. 这很容易做到。 Of course, the encryption key is going to have to be stored in the app somewhere, so unless you're obfuscating your code a determined hacker will be able to get to it. 当然,加密密钥必须存储在应用程序的某个地方,因此,除非您对代码进行模糊处理,否则确定的黑客将能够访问它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM