IUse the XSD mode file to verify the XML file:
XML file:
<?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 file:
<?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>
Verification Code:
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; }
Call code:
String xmlpath = "books. xml ";
String XSD = "books. XSD ";
String message = string. empty;
Bool validate = xmlvalidate (xmlpath, XSD, out message );
IIWhen querying XML data, pay attention to XQuery injection (XPath injection ).), Usually the XPath statement is as follows:
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(); }
But such code is very vulnerable to attacks, here we use MVP. XML (Open Source library http://mvpxml.codeplex.com/) to achieve parameterized query, to prevent XQuery injection.
Modified code:
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(); }
Symmetric encryption, Encrypt XML nodes
Create an XML file as follows:
<?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>
The encryption and decryption code is as follows:
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); }
The call method is as follows:
String xmlpath = "encrypt. xml ";
Xmldocument document = new xmldocument ();
Document. Load (xmlpath );
Rijndaelmanaged Rijndael = new rijndaelmanaged ();
Encrypt (document, "message", Rijndael );
Decrypt (document, Rijndael );
Encrypted data
Use non-pair encryption technology, Encrypt XML nodes
The encryption and decryption code is as follows:
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(); }
The code is called as follows:
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 ");
};
Running result
Use asymmetric key to sign XML
The implementation code is as follows:
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); }
The call code is as follows:
String xmlpath = "encrypt. xml ";
Xmldocument document = new xmldocument ();
Document. preservewhitespace = true;
Document. Load (xmlpath );
Rsacryptoserviceprovider RSA = new rsacryptoserviceprovider ();
Signxml (document, RSA );
Issignedxmlvalid (document, RSA );
Running result
I personally think that the use of certificates in XML is not common and is simple. This is omitted here.
Summary:
Before using XML, you must use a strict Schema (schema file) for verification and try to use local copies of the schema so that the cache parser can cache them.
Select an appropriate encryption algorithm. If the application needs to encrypt and decrypt the same application, select symmetric encryption. If the application needs to communicate with the external system, select asymmetric encryption.
If you need to make sure that the data is not changed, you must always use a digital signature.