zoukankan      html  css  js  c++  java
  • C# xml 常规 保护 方法总结

     使用xsd模式文件验证xml文件

    xml文件:

    <?xml version="1.0" encoding="utf-8" ?>
    <Books>
      <Book>
        <Title>ExampleTitle</Title>
        <Author>John Smith</Author>
        <Pages>500</Pages>
      </Book>
    <Book>
        <Title>Another Title</Title>
        <Author>John Doe</Author>
        <Pages>250</Pages>
      </Book>
    </Books>
    

     xsd文件:

    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="Books">
        <xs:complexType>
          <xs:sequence>
            <xs:element maxOccurs="unbounded" name="Book">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="Title" type="xs:string" minOccurs="1" maxOccurs="1" />
                  <xs:element name="Author" type="xs:string" />
                  <xs:element name="Pages" type="xs:unsignedShort" minOccurs="1" maxOccurs="1" />
                </xs:sequence>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>
    

     验证代码:

       static bool XmlValidate(string xmlPath, string xsdPath, out string message)
            {
                bool isXmlValid = true;
                string errorMessage = string.Empty;
                XmlReaderSettings settings = new XmlReaderSettings()
                {
                    ValidationType = ValidationType.Schema,
                    ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings
                };
                settings.ValidationEventHandler += (o, e) =>
                {
                    isXmlValid = false;
                    errorMessage = e.Message;
                };
                XmlSchema schema = XmlSchema.Read(new StreamReader(xsdPath), null);
                settings.Schemas.Add(schema);
                XmlDocument xmlDocument = new XmlDocument();
                XmlReader xmlReader = XmlReader.Create(xmlPath, settings);
                xmlDocument.Load(xmlReader);
                message = errorMessage;
                return isXmlValid;
            }
    

     调用代码:

      string xmlPath = "books.xml";
                string xsd = "books.xsd";
                string message = string.Empty;
                bool validate = XmlValidate(xmlPath, xsd, out message);

    xml查询时需要注意XQuery注入(XPath注入),通常xPath语句如下:

    static string GetBookTitle(string author, int page)
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.Load("books.xml");
                XPathNavigator navigator = xmlDocument.CreateNavigator();
                string xquery = string.Format("string(//Book[Author/text()='{0}' and Pages/text()={1}]/Title/text())", author, page.ToString());
                XPathExpression expression = navigator.Compile(xquery);
                return navigator.Evaluate(expression).ToString();
            }
    

     但是这样的代码很容易遭到攻击,这里我们用Mvp.xml(开源库http://mvpxml.codeplex.com/)来实现参数化查询,防止xquery注入。

     修改后的代码:

       static string GetBookTitle(string author, int page)
            {
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.Load("books.xml");
                string xquery = "string(//Book[Author/text()=$author and Pages/text()=$page]/Title/text())";
                XPathNavigator navigator = xmlDocument.CreateNavigator();
                XPathExpression expression = DynamicContext.Compile(xquery);
    
                DynamicContext ctx = new DynamicContext();
                ctx.AddVariable("author", author);
                ctx.AddVariable("page",page.ToString());
                expression.SetContext(ctx);
    
                return navigator.Evaluate(expression).ToString();
            }

    采用对称加密,加密xml节点新建xml文件如下: 

    <?xml version="1.0" encoding="utf-8" ?>
    <envelope>
      <to>ma.jiang@wipro.com</to>
      <from>gavin_ma@vfc.com</from>
      <message>You have just been paid.</message>
    </envelope>
    

    加密和解密代码如下:

      static void Encrypt(XmlDocument document, string elementNameToEntrypt, SymmetricAlgorithm algorithm)
            {
                if (document == null)
                    throw new ArgumentNullException("document");
                if (elementNameToEntrypt == null)
                    throw new ArgumentNullException("elementNameToEntrypt");
                if (algorithm == null)
                    throw new ArgumentNullException("key");
                XmlElement elementToEncrypt = document.GetElementsByTagName(elementNameToEntrypt)[0] as XmlElement;
                if (elementToEncrypt == null)
                    throw new XmlException("The specified element was not found");
                EncryptedXml exml = new EncryptedXml();
    
                byte[] encryptedElement = exml.EncryptData(elementToEncrypt, algorithm, false);
                EncryptedData encryptedData = new EncryptedData { Type = EncryptedXml.XmlEncElementUrl };
                string encryptionMethod = string.Empty;
                if (algorithm is TripleDES)
                    encryptionMethod = EncryptedXml.XmlEncTripleDESUrl;
                else if (algorithm is DES)
                    encryptionMethod = EncryptedXml.XmlEncDESUrl;
                else if (algorithm is Rijndael)
                {
                    switch (algorithm.KeySize)
                    {
                        case 128:
                            encryptionMethod = EncryptedXml.XmlEncAES128Url;
                            break;
                        case 192:
                            encryptionMethod = EncryptedXml.XmlEncAES192Url;
                            break;
                        case 256:
                            encryptionMethod = EncryptedXml.XmlEncAES256Url;
                            break;
                    }
                }
                else
                {
                    throw new CryptographicException("Specificed algorithm is not supported");
                }
                encryptedData.EncryptionMethod = new EncryptionMethod(encryptionMethod);
                encryptedData.CipherData.CipherValue = encryptedElement;
                EncryptedXml.ReplaceElement(elementToEncrypt, encryptedData, false);
            }
            static void Decrypt(XmlDocument document, SymmetricAlgorithm algorithm)
            {
                if (document == null)
                    throw new ArgumentNullException("document");
               
                if (algorithm == null)
                    throw new ArgumentNullException("key");
                XmlElement encryptedElement = document.GetElementsByTagName("EncryptedData")[0] as XmlElement;
                if (encryptedElement == null)
                    throw new XmlException("No encrypted element was found.");
                EncryptedData encryptedData = new EncryptedData();
                encryptedData.LoadXml(encryptedElement);
                EncryptedXml encryptedXml = new EncryptedXml();
                byte[] rgbOutput = encryptedXml.DecryptData(encryptedData, algorithm);
                encryptedXml.ReplaceData(encryptedElement,rgbOutput);
            }
    

     调用方法如下:

       string xmlPath = "encrypt.xml";
                XmlDocument document = new XmlDocument();
                document.Load(xmlPath);
                RijndaelManaged rijndael = new RijndaelManaged();
                Encrypt(document, "message", rijndael);
                Decrypt(document, rijndael);

    加密后的数据如图:

     采用非对成加密技术,加密xml节点

    加密和解密代码如下:

      public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, string EncryptionElementID, RSA Alg, string KeyName)
            {
                // Check the arguments.
                if (Doc == null)
                    throw new ArgumentNullException("Doc");
                if (ElementToEncrypt == null)
                    throw new ArgumentNullException("ElementToEncrypt");
                if (EncryptionElementID == null)
                    throw new ArgumentNullException("EncryptionElementID");
                if (Alg == null)
                    throw new ArgumentNullException("Alg");
                if (KeyName == null)
                    throw new ArgumentNullException("KeyName");
    
                ////////////////////////////////////////////////
                // Find the specified element in the XmlDocument
                // object and create a new XmlElemnt object.
                ////////////////////////////////////////////////
                XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
    
                // Throw an XmlException if the element was not found.
                if (elementToEncrypt == null)
                {
                    throw new XmlException("The specified element was not found");
    
                }
                RijndaelManaged sessionKey = null;
    
                try
                {
                    //////////////////////////////////////////////////
                    // Create a new instance of the EncryptedXml class
                    // and use it to encrypt the XmlElement with the
                    // a new random symmetric key.
                    //////////////////////////////////////////////////
    
                    // Create a 256 bit Rijndael key.
                    sessionKey = new RijndaelManaged();
                    sessionKey.KeySize = 256;
    
                    EncryptedXml eXml = new EncryptedXml();
    
                    byte[] encryptedElement = eXml.EncryptData(elementToEncrypt, sessionKey, false);
                    ////////////////////////////////////////////////
                    // Construct an EncryptedData object and populate
                    // it with the desired encryption information.
                    ////////////////////////////////////////////////
    
                    EncryptedData edElement = new EncryptedData();
                    edElement.Type = EncryptedXml.XmlEncElementUrl;
                    edElement.Id = EncryptionElementID;
                    // Create an EncryptionMethod element so that the
                    // receiver knows which algorithm to use for decryption.
    
                    edElement.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncAES256Url);
                    // Encrypt the session key and add it to an EncryptedKey element.
                    EncryptedKey ek = new EncryptedKey();
    
                    byte[] encryptedKey = EncryptedXml.EncryptKey(sessionKey.Key, Alg, false);
    
                    ek.CipherData = new CipherData(encryptedKey);
    
                    ek.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSA15Url);
    
                    // Create a new DataReference element
                    // for the KeyInfo element.  This optional
                    // element specifies which EncryptedData
                    // uses this key.  An XML document can have
                    // multiple EncryptedData elements that use
                    // different keys.
                    DataReference dRef = new DataReference();
    
                    // Specify the EncryptedData URI.
                    dRef.Uri = "#" + EncryptionElementID;
    
                    // Add the DataReference to the EncryptedKey.
                    ek.AddReference(dRef);
                    // Add the encrypted key to the
                    // EncryptedData object.
    
                    edElement.KeyInfo.AddClause(new KeyInfoEncryptedKey(ek));
                    // Set the KeyInfo element to specify the
                    // name of the RSA key.
    
    
                    // Create a new KeyInfoName element.
                    KeyInfoName kin = new KeyInfoName();
    
                    // Specify a name for the key.
                    kin.Value = KeyName;
    
                    // Add the KeyInfoName element to the
                    // EncryptedKey object.
                    ek.KeyInfo.AddClause(kin);
                    // Add the encrypted element data to the
                    // EncryptedData object.
                    edElement.CipherData.CipherValue = encryptedElement;
                    ////////////////////////////////////////////////////
                    // Replace the element from the original XmlDocument
                    // object with the EncryptedData element.
                    ////////////////////////////////////////////////////
                    EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
                }
                catch (Exception e)
                {
                    // re-throw the exception.
                    throw e;
                }
                finally
                {
                    if (sessionKey != null)
                    {
                        sessionKey.Clear();
                    }
    
                }
    
            }
    
            public static void Decrypt(XmlDocument Doc, RSA Alg, string KeyName)
            {
                // Check the arguments.  
                if (Doc == null)
                    throw new ArgumentNullException("Doc");
                if (Alg == null)
                    throw new ArgumentNullException("Alg");
                if (KeyName == null)
                    throw new ArgumentNullException("KeyName");
    
                // Create a new EncryptedXml object.
                EncryptedXml exml = new EncryptedXml(Doc);
    
                // Add a key-name mapping.
                // This method can only decrypt documents
                // that present the specified key name.
                exml.AddKeyNameMapping(KeyName, Alg);
    
                // Decrypt the element.
                exml.DecryptDocument();
    
            }
    

     代码调用如下:

               string xmlPath = "encrypt.xml";
                XmlDocument document = new XmlDocument();
                document.PreserveWhitespace = true;
                document.Load(xmlPath);
                UnicodeEncoding ByteConverter = new UnicodeEncoding();
                CspParameters cspParams = new CspParameters { KeyContainerName = "XML_ENC_RSA_KEY" };
                using ( RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams))
                {
                    Encrypt(document, "message", "EncryptedElementID", rsaKey, "rsaKey");
                    // document.Save("test.xml");
                         Decrypt(document, rsaKey, "rsaKey");
                };

    运行结果如图:

     用非对称密钥签名xml

    实现代码如下:

      static void SignXml(XmlDocument document, RSA algorithm)
            {
                SignedXml signxml = new SignedXml(document) { SigningKey = algorithm };
                Reference reference = new Reference { Uri = string.Empty };
                XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
                reference.AddTransform(env);
                signxml.AddReference(reference);
                signxml.ComputeSignature();
                XmlElement xmlDigitalSignature = signxml.GetXml();
                document.DocumentElement.AppendChild(document.ImportNode(xmlDigitalSignature,true));
            }
            static bool IsSignedXmlValid(XmlDocument document, RSA algorithm)
            {
                SignedXml signxml = new SignedXml(document);
                XmlNodeList nodelist = document.GetElementsByTagName("Signature");
                if (nodelist.Count < 1)
                {
                    throw new CryptographicException("No signature found");
                }
                signxml.LoadXml((XmlElement)nodelist[0]);
                return signxml.CheckSignature(algorithm);
            }
    View Code

    调用代码如下:

      string xmlPath = "encrypt.xml";
                XmlDocument document = new XmlDocument();
                document.PreserveWhitespace = true;
                document.Load(xmlPath);
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                SignXml(document, rsa);
                IsSignedXmlValid(document, rsa);

    运行结果如图:

    个人认为证书在xml中使用情况不常见,并且也比较简单,这里就省略了。

    总结一下:

    在使用xml之前,必须使用严格的架构(模式文件)来验证,尽可能使用架构的本地副本,以便缓存解析器来缓存他们。

    选择一个合适的加密算法,如果应用程序需要加密和解密相同的应用程序,那么选择对称加密;应用程序需要和外部系统进行交流,那么选择非对称加密。

    如果需要确保数据没有被更改,就需要始终使用数字签名

  • 相关阅读:
    Codeforces Round #567 (Div. 2) B. Split a Number
    es界面的分组,求平均值的操作
    es界面的查询命令
    es界面的crud
    WebStorm中自定义文档注释模板
    Vue 正确理解mounted、beforeUpdate、updated三个钩子函数的关系
    oracle分析函数
    vue中时间格式的处理
    vue-router params和query的区别
    vue中的深拷贝理解和实现
  • 原文地址:https://www.cnblogs.com/majiang/p/3174904.html
Copyright © 2011-2022 走看看