为 .NET 中的 XMLSerialized 对象生成哈希签名 (HMAC) 的最佳方法?
我需要为使用 .NET 框架中的 XMLSerializer 序列化的对象生成 HMAC。每个对象将包含一个名为“HMAC”的属性,该属性将包含对象值本身的哈希值,但不包括“HMAC”字段。我发现这个问题提到CLR 中的内置解决方案,但没有详细说明其名称或我如何使用它?
示例对象看起来像这样:
[Serializable]
[XmlRoot("request", IsNullable = false)]
public class Request
{
[XmlElement(ElementName = "hmac")]
public string Hmac { get; set; }
[XmlElement(ElementName = "nonce")]
public string Nonce { get; set; }
[XmlElement(ElementName = "expiration")]
public DateTime Expiration { get; set; }
/* A bunch of other properties to be serialized */
private Request() { }
public Request(string hmac, string nonce, DateTime expiration)
{
Hmac = hmac;
Nonce = nonce;
Expiration = expiration;
}
}
HMAC 属性需要设置为整个对象的序列化,不包括 HMAC 对象本身。我的第一个想法是设置某种两遍序列化,其中涉及:
- 在第一遍上为 HMAC 对象设置 xmlignore 属性
- 序列化整个对象 对
- 结果进行哈希处理,并设置 HMAC 属性的值
- 重新序列化整个对象事情再次发生,准备传输。
这是最好的方法吗?以前有人做过类似的事情吗?您发现什么是最干净的方法???
I need to generate a HMAC for objects that I am serializing using the XMLSerializer found in the .NET framework. Each object will contain a property called "HMAC" that will contain a hash of the object's values itself but excluding the "HMAC" field. I've found this question that mentions a built-in solution within the CLR but doesn't elaborate on exactly what its called or how I go about using it?
A sample object would look something like this:
[Serializable]
[XmlRoot("request", IsNullable = false)]
public class Request
{
[XmlElement(ElementName = "hmac")]
public string Hmac { get; set; }
[XmlElement(ElementName = "nonce")]
public string Nonce { get; set; }
[XmlElement(ElementName = "expiration")]
public DateTime Expiration { get; set; }
/* A bunch of other properties to be serialized */
private Request() { }
public Request(string hmac, string nonce, DateTime expiration)
{
Hmac = hmac;
Nonce = nonce;
Expiration = expiration;
}
}
The HMAC property will need to be set as a serialization of the entire object, excluding the HMAC object itself. My first thoughts are setting up some sort of two-pass serialization, which involves:
- Setting an xmlignore property to the HMAC object on the first pass
- Serializing the entire object
- Hashing the result, and setting the value of the HMAC property
- Re-serializing the whole thing again, ready for transmission.
Is this the best way to go about it? Has anyone done anything like this before, and what have you found to be the cleanest way of going about it???
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为你必须将其序列化两次才能获得你所描述的确切效果。一种更简单的方法是不使用 XmlIgnore,而是添加一个公共指定属性(.NET XML 序列化专门处理该属性,以编程方式控制是否发出类似命名的属性):
这只会发出
hmac
XML 节点(如果存在)。使用DefaultValueAttribute
可以实现类似的效果,但我发现它存在一些不一致之处(例如,null
有时在编译期间被替换为""
)。另外,如果您的逻辑比单个常量哨兵值更复杂,您可以在属性中处理它,但不能在静态属性中处理。如果格式必须与您所描述的完全匹配,我就会这样做。
如果输出格式具有灵活性,您可能会考虑使用一个消息容器,其中包含消息正文(您当前的 XML 文档)和 HMAC 签名值。这样您只需序列化文档一次。
即使信封是较大序列化文档的一部分,您也可以在信封上实现 IXmlSerialized.WriteXml 接口。这将允许您仔细地将消息序列化为字符串,然后执行哈希,然后通过
XmlWriter.WriteRaw
将 HMAC 和消息元素全部写出。如果性能很重要,我就会这样做。
I think you will have to serialize it twice to get the exact effect you described. One way to make that easier would be to not use XmlIgnore but instead add a public specified property (which .NET XML serialization treats specially to programmatically control whether to emit the similarly named property):
What this will do is only emit the
hmac
XML node if one exists. A similar effect could be achieved with theDefaultValueAttribute
but I've found some inconsistencies with it (e.g.null
is sometimes replaced with""
during compilation). Plus if your logic was more complex than a single contant sentinel value you could handle that in the property but not in a static attribute.This would be the way I would do it if the format had to exactly match what you've described.
If you have flexibility in the output format, another approach you might consider is having a message container which contains the message body (your current XML doc) and an HMAC Signature value. This way you would only need to serialize the document once.
Even if the envelope were part of a larger serialization document you could implement an
IXmlSerializable.WriteXml
interface on the envelope. This would allow you to carefully serialize the message to a string, then perform the hash, then write out the HMAC and message elements all in one viaXmlWriter.WriteRaw
.This would be the way I would do it if performance was important.