Windows更新后KeyInfo加载失败,求无需修改注册表的解决方案
解决Windows更新后KeyInfo加载的"Malformed element keyinfo"异常
我之前也碰到过一模一样的问题——Windows某次更新后,.NET的EncryptedKey.LoadXml()突然对KeyInfo节点的属性校验变严格了,带xsi:type="KeyInfoType"的节点直接抛出SecurityException。下面给你几个不用改注册表、也不用手动删属性的可行方案:
方案1:自定义SignedXml绕过KeyInfo校验
你可以继承SignedXml类,重写它读取KeyInfo的方法,临时关闭XML的校验规则,这样就能跳过对xsi:type属性的检查。代码示例如下:
public class RelaxedSignedXml : SignedXml { public RelaxedSignedXml(XmlDocument doc) : base(doc) { } public RelaxedSignedXml(XmlElement elem) : base(elem) { } protected override KeyInfo ReadKeyInfo(XmlReader reader) { // 保存原始读取器设置,创建一个禁用校验的新设置 var originalSettings = reader.Settings; var relaxedSettings = new XmlReaderSettings { ValidationType = ValidationType.None, IgnoreWhitespace = originalSettings?.IgnoreWhitespace ?? true, IgnoreComments = originalSettings?.IgnoreComments ?? true }; // 用宽松设置的读取器读取KeyInfo using var relaxedReader = XmlReader.Create(reader, relaxedSettings); relaxedReader.MoveToContent(); return base.ReadKeyInfo(relaxedReader); } }
之后你可以用这个自定义类来处理加密/签名操作,或者配合EncryptedKey使用,就能正常加载带xsi:type属性的KeyInfo节点了。
方案2:用包装XmlReader过滤冗余属性
如果你不想修改SignedXml的逻辑,可以创建一个包装类的XmlReader,在读取KeyInfo节点时自动过滤掉xsi:type属性,不用修改原始XML字符串:
public class KeyInfoCleanupReader : XmlReader { private readonly XmlReader _innerReader; private List<XmlAttribute> _filteredAttributes; private bool _isKeyInfoElement; public KeyInfoCleanupReader(XmlReader innerReader) { _innerReader = innerReader; } // 重写核心读取逻辑 public override bool Read() { bool result = _innerReader.Read(); if (result && _innerReader.NodeType == XmlNodeType.Element && _innerReader.LocalName == "KeyInfo" && _innerReader.NamespaceURI == "http://www.w3.org/2000/09/xmldsig#") { _isKeyInfoElement = true; // 过滤掉xsi:type属性 _filteredAttributes = new List<XmlAttribute>(); for (int i = 0; i < _innerReader.AttributeCount; i++) { _innerReader.MoveToAttribute(i); if (!(_innerReader.NamespaceURI == "http://www.w3.org/2001/XMLSchema-instance" && _innerReader.LocalName == "type")) { var attr = (XmlAttribute)_innerReader.ReadOuterXml(); _filteredAttributes.Add(attr); } } _innerReader.MoveToElement(); } else { _isKeyInfoElement = false; } return result; } // 重写属性相关方法,返回过滤后的结果 public override int AttributeCount => _isKeyInfoElement ? _filteredAttributes.Count : _innerReader.AttributeCount; public override string GetAttribute(int i) { return _isKeyInfoElement ? _filteredAttributes[i].Value : _innerReader.GetAttribute(i); } // 补充重写其他必要的XmlReader抽象方法 public override XmlNodeType NodeType => _innerReader.NodeType; public override string LocalName => _innerReader.LocalName; public override string NamespaceURI => _innerReader.NamespaceURI; public override bool EOF => _innerReader.EOF; public override string Value => _innerReader.Value; // 其他方法按需补充... }
使用的时候,用这个包装后的读取器加载XML:
var xmlDoc = new XmlDocument(); using var stringReader = new StringReader(rawData); using var originalReader = XmlReader.Create(stringReader); using var cleanedReader = new KeyInfoCleanupReader(originalReader); xmlDoc.Load(cleanedReader); var encryptedKey = new EncryptedKey(); encryptedKey.LoadXml(xmlDoc.DocumentElement);
关于Windows更新的原因
目前微软官方没有针对这个变更的明确公开说明,但推测是某次.NET Framework的安全更新收紧了XML数字签名相关节点的Schema校验规则——xsi:type="KeyInfoType"属于冗余属性(KeyInfo本身就是这个类型),之前的版本允许这种冗余,更新后被判定为格式错误。你可以查看近期的.NET Framework安全更新公告,可能会找到相关的变更细节。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

