您的位置:首页 > 编程语言 > C#

C# xml 常规 保护 方法总结

2013-07-06 17:37 288 查看
使用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);

加密后的数据如图:

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之前,必须使用严格的架构(模式文件)来验证,尽可能使用架构的本地副本,以便缓存解析器来缓存他们。

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

如果需要确保数据没有被更改,就需要始终使用数字签名
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: