【问题标题】:When do xmlns get checked?什么时候检查 xmlns?
【发布时间】:2021-06-23 10:02:17
【问题描述】:

我正在使用 C# XmlSerializer 反序列化一些在其中一部分具有 xmlns 声明的 XML(请注意,我截断了 CipherValue 以适应这篇文章):

<EncryptedData
  Id="ZbjUzHbD37LI2DEuiEGX6A7PSnQ+19dutLPiDxZqnFY=3NLz2QA5KCiXVlJSXejhDQ=="
  Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#"
  length="44">
  <EncryptionMethod
    Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
  <CipherData>
    <CipherValue>3NLz2QA5KCiXVlJSXejhDZYYa9sLbv/w42....+PsLMCfRFN//StgbYoRqno3WQ==</CipherValue>
  </CipherData>
</EncryptedData>

将此 XML 加载到 Visual Studio 中后,VS 会突出显示 Id 属性中的“+”字符,并且将长度属性的存在视为错误。我假设 VS 可以知道这一点的唯一方法是,它是否检查了 Type 和 xmlns 属性中的 URL。 VS 发出这种类型的 Internet 请求对我来说是可以的,因为我已授予 VS 执行检查更新等操作的权限,所以我已经知道它将按照自己的条件访问 Internet。

但是,除非我删除 xmlns(或通过自定义 XML 文本阅读器强制使用空白命名空间),否则上述 XML 不会在我的命令行程序中反序列化,因此我假设我的命令行程序也在验证 xmlns通过访问该 URL。

这对我来说有点麻烦,虽然我知道什么是 xmlns URL,但我没有明确授予我的程序访问 Internet 的权限。此外,该程序的用例在本地运行,并分析由另一个本地唯一程序生成的一些 XML。它可能会发出 Internet 请求的想法远未引起我的注意。

除了反序列化这个 XML,我还使用 c# XslCompiledTransform 类做一些 XSLT。我最终意识到,在执行转换时,xmlns 属性不是您可以使用 XSLT 操作的,因为转换是在 XML 的概念数据上执行的,而不是在原始 XML 字符串上执行的。因此,转换在读取 XML 时以某种方式处理了 xmlns。

我的问题是:

  1. XmlSerializer 类是否与 xmlns 建立隐式 Internet 连接?
  2. XslCompiledTransform 类是否在做类似的事情?
  3. 如果存在隐式连接,它们是否存在安全风险?
  4. 如果是这样,可以采取什么措施来缓解它(除了强制使用空白命名空间)?

根据@canton 的要求,这是我用于 EncryptedData 的类定义,以及显示其引用位置的片段

    ...
    [XmlElement("EncryptedData")]
    public EncryptedData EncryptedData { get; set; }
    ...

    public class EncryptedData
    {
        [XmlAttribute("Id")]
        public string Id { get; set; }

        [XmlAttribute("Type")]
        public string Type { get; set; }

        [XmlAttribute("xmlns")]
        public string Xmlns { get; set; }

        [XmlAttribute("length")]
        public int Length { get; set; }

        [XmlElement("EncryptionMethod")]
        public EncryptionMethod EncryptionMethod { get; set; }

        [XmlElement("CipherData")]
        public CipherData CipherData { get; set; }
   }

【问题讨论】:

  • 你如何反序列化这个?请发布您的代码。特别是,您可能会将一些属性放入正确的命名空间中(例如[XmlElement(Namespace = .....)]
  • 可能 VS 已经知道http://www.w3.org/2001/04/xmlenc#,不需要上网,但我不确定
  • 命名空间只要可达就会被验证,否则会被忽略。为了使序列化工作,xml 中的命名空间和 c# 类中声明的命名空间必须匹配。如果未指定,则默认为空字符串。
  • @jdweng 这是不正确的——没有验证命名空间的概念。您针对 XSD 进行验证,但即便如此,也只有在您提出要求时才会这样做
  • @canton7 可以的

标签: c# xml url xslt deserialization


【解决方案1】:

首先,命名空间不是 URL!命名空间只是一个任意字符串。它们通常看起来像 URL 的原因是,如果每个人都使用他们拥有或控制的域下的 URL,那么名称就不会与其他任何人的同名元素发生冲突。即使命名空间是 URL 形式,通常也没有任何实际存在的东西,也没有工具会尝试访问它。

Visual Studio 为所有 Microsoft 和标准架构维护一个架构文件目录。如果您在编辑 XML 时需要智能感知,可以在此处添加自己的。检查该位置的文档。

在没有 VS 已知的 xsd 的情况下,VS 或 XmlSerializer 理解的唯一属性是 xmlns。

您的反序列化器无法工作的原因是您的元素需要知道命名空间。很容易错过这一点,因为您将在 Internet 上看到的所有示例都倾向于不使用命名空间。

进行反序列化的一个好方法是使用 xsd.exe 从 xsd 架构或示例数据文件生成类 - 生成的代码很糟糕,但可以引导你使用更漂亮的版本 - 如果你这样做了,你会看到生成代码上的属性包括一个命名空间,例如

[XmlElement("EncryptedData", Namespace="http://www.w3.org/2001/04/xmlenc#"]

当手动创建它时,将命名空间放在 const 字符串中显然更简洁。

关于什么有和没有命名空间限定符的规则可能会很混乱,因此我建议首先生成示例代码。

如果您确实需要架构验证,则必须通过将验证 XmlReader 传递给 XmlSerializer 自己明确地进行验证,即验证是可选的,作为读取 XML 的一部分,而不是作为反序列化的一部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多