【问题标题】:Encrypting properties before saving class to xml file在将类保存到 xml 文件之前加密属性
【发布时间】:2019-11-12 17:47:49
【问题描述】:

我正在尝试将一些连接字符串作为加密文本保存到我班级的 XML 中。

这是我的课:

using System.Data.SqlClient;
using TechGuyComputing.CompleteOrganizerWPF.Data;

namespace TechGuyComputing.CompleteOrganizerWPF.MiscClasses
{
  public class AppSetting
  {
    private string _dataSource;
    private string _intitialCatalog;
    private string _userId;
    private string _password;

    public string DataSource
    {
      set => _dataSource = Encryption.SimpleEncryptWithPassword(value, GlobalConstants.EncryptionPassword);
      get => Encryption.SimpleDecryptWithPassword(_dataSource, GlobalConstants.EncryptionPassword);
    }

    public string IntitialCatalog
    {
      set => _intitialCatalog = Encryption.SimpleEncryptWithPassword(value, GlobalConstants.EncryptionPassword);
      get => Encryption.SimpleDecryptWithPassword(_intitialCatalog, GlobalConstants.EncryptionPassword);
    }

    public string UserId
    {
      set => _userId = Encryption.SimpleEncryptWithPassword(value, GlobalConstants.EncryptionPassword);
      get => Encryption.SimpleDecryptWithPassword(_userId, GlobalConstants.EncryptionPassword);
    }

    public string Password
    {
      set => _password = Encryption.SimpleEncryptWithPassword(value, GlobalConstants.EncryptionPassword);
      get => Encryption.SimpleDecryptWithPassword(_password, GlobalConstants.EncryptionPassword);
    }

    public bool IntegratedSecurity { set; get; }
    public bool MultipleActiveResultSets { set; get; }
    public bool PersistSecurityInfo { set; get; }
  }

  internal static class AppSettings
  {
    public static AppSetting ApplicationSettings;

    public static SqlConnection ConnectionString { get; private set; }


    static AppSettings()
    {
      if (ApplicationSettings == null)
      {
        ApplicationSettings = XmlReader.GetAppSettingsFromXmlFile();
        SetConnectionString();
      }
    }

    public static void SaveAppSettings()
    {
      if (ApplicationSettings == null)
      {
        ApplicationSettings = new AppSetting();
      }
      XmlReader.WriteAppSettingsToXmlFile(ApplicationSettings);
      SetConnectionString();
    }

    private static void SetConnectionString()
    {
      if (string.IsNullOrEmpty(ApplicationSettings.DataSource) || string.IsNullOrEmpty(ApplicationSettings.IntitialCatalog))
      {
        ConnectionString = new SqlConnection();
        return;
      }

      var builder = new SqlConnectionStringBuilder
      {
        DataSource = ApplicationSettings.DataSource,
        InitialCatalog = ApplicationSettings.IntitialCatalog,
        IntegratedSecurity = ApplicationSettings.IntegratedSecurity,
        MultipleActiveResultSets = ApplicationSettings.MultipleActiveResultSets,
        PersistSecurityInfo = ApplicationSettings.PersistSecurityInfo,
        UserID = ApplicationSettings.UserId,
        Password = ApplicationSettings.Password
      };

      ConnectionString = new SqlConnection(builder.ConnectionString);
    }

  }
}

这就是我保存 XML 文件的方式:

using System.IO;
using System.Xml.Serialization;

namespace TechGuyComputing.CompleteOrganizerWPF.MiscClasses
{
  internal static class XmlReader
  {

    public static void WriteAppSettingsToXmlFile(AppSetting appSetting)
    {
      var xs = new XmlSerializer(typeof(AppSetting));
      var tw = new StreamWriter(GlobalConstants.XmlFile);
      xs.Serialize(tw, appSetting);
    }

    public static AppSetting GetAppSettingsFromXmlFile()
    {
      if (!File.Exists(GlobalConstants.XmlFile))
      {
        return new AppSetting();
      }

      using (var sr = new StreamReader(GlobalConstants.XmlFile))
      {
        XmlSerializer xs = new XmlSerializer(typeof(AppSetting));
        return (AppSetting)xs.Deserialize(sr);
      }
    }


  }
}

我的保存工作正常,但它没有将值保存为加密字符串。

我认为这可以即时处理它,但它什么也没做:

public string DataSource
{
  set => _dataSource = Encryption.SimpleEncryptWithPassword(value, GlobalConstants.EncryptionPassword);
  get => Encryption.SimpleDecryptWithPassword(_dataSource, GlobalConstants.EncryptionPassword);
}

我没有收到任何错误消息,只是没有加密数据。

任何建议我如何在保存某些属性之前对其进行加密?

编辑: 如果可以防止它,我宁愿不加密整个文件。我只想加密我选择的属性。

【问题讨论】:

    标签: c# encryption xmlserializer


    【解决方案1】:

    您的问题是 XmlSerializer 仅序列化 public 属性和字段 - 您的 AppSetting 类中的公共属性都是未加密的。来自docs

    XML 序列化仅将对象的公共字段和属性值序列化为 XML 流。 ...

    XML 序列化不会转换方法、索引器、私有字段或只读属性(只读集合除外)。要序列化对象的所有字段和属性,包括公共的和私有的,请使用DataContractSerializer 而不是 XML 序列化。

    因此您的选择是:

    1. 为加密成员创建公共属性并使用XmlIgnore 标记明文属性,如下所示:

      [System.ComponentModel.Browsable(false), System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never), System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
      [XmlElement("DataSource")] // Optionally change the element name to be <DataSource>
      public string EncryptedDataSource { get; set; }
      
      [XmlIgnore]
      public string DataSource
      {
          set => EncryptedDataSource = Encryption.SimpleEncryptWithPassword(value, GlobalConstants.EncryptionPassword);
          get => Encryption.SimpleDecryptWithPassword(EncryptedDataSource, GlobalConstants.EncryptionPassword);
      }
      

      演示小提琴#1 here.

    2. 切换到DataContractSerializer。首先修改你的类如下:

      [DataContract]
      public class AppSetting
      {
          [DataMember(Name = "DataSource")]
          private string _dataSource;
          [DataMember(Name = "IntitialCatalog")]
          private string _intitialCatalog;
          [DataMember(Name = "UserId")]
          private string _userId;
          [DataMember(Name = "Password")]
          private string _password;
      
          // Remainder unchanged
      

      然后修改XmlReader如下:

      public static void WriteAppSettingsToXmlFile(AppSetting appSetting)
      {
          var serializer = new DataContractSerializer(typeof(AppSetting));
          using (var stream = new FileStream(GlobalConstants.XmlFile, FileMode.Create))
          {
              serializer.WriteObject(stream, appSetting);
          }
      }
      
      public static AppSetting GetAppSettingsFromXmlFile()
      {
          if (!File.Exists(GlobalConstants.XmlFile))
          {
              return new AppSetting();
          }
          using (var stream = File.OpenRead(GlobalConstants.XmlFile))
          {
              var serializer = new DataContractSerializer(typeof(AppSetting));
              return (AppSetting)serializer.ReadObject(stream);
          }
      }
      

      生成的属性都将被加密。

      演示小提琴#2 here.

    注意事项:

    • WriteAppSettingsToXmlFile() 中,您不处置StreamWriter。这将使文件保持打开状态,并可能在以后导致错误。相反,这样做:

      public static void WriteAppSettingsToXmlFile(AppSetting appSetting)
      {
          var xs = new XmlSerializer(typeof(AppSetting));
          using (var tw = new StreamWriter(GlobalConstants.XmlFile))
          {
              xs.Serialize(tw, appSetting);
          }
      }
      
    • 虽然用XmlSerializer 序列化的属性必须是公开的,但您可以通过用[Browsable(false)][EditorBrowsable(EditorBrowsableState.Never)][DebuggerBrowsable(DebuggerBrowsableState.Never)] 标记它们来稍微隐藏它们,

    【讨论】:

    • 这真是太棒了!很棒的工作 tyvm!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多