内容纲要

XXE是基于XML的 , 所以得先看XML

定义 : XML用于标记电子文件 , 使其具有结构性的标记语言 , XML常被用于传输数据 和存储数据 . 它的标签都没有被预定义 , 需要用户自行定义 . 是一种允许用户对自己的标记语言进行定义的源语言 , 具有自我描述性

XML由三个部分构成 :

  • DTD : Document Type Definition 文档类型定义( 也被称为 " XML布局语言 " )

  • XSL : Extensible Style Language 可扩展样式语言 ( 也被称为 : " XML样式表语言 " )

  • XLL : Extensible LInk Language 可扩展链接语言

 

XML文档由三个部分组成

  • XML声明

  • DTD ( 文档类型定义 , 这是可选的 )

  • 文档元素

 

一个简单的XML文档
<!-- XML声明 -->
<?xml version="1.0" ?>

<!-- DTD 文档类型定义 -->
!DOCTYPE note [    <!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)>     <!--定义note元素有四个元素-->
<!ELEMENT to (#PCDATA)>    <!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)>    <!--定义from元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)>    <!--定义head元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)>    <!--定义body元素为”#PCDATA”类型-->
]>

<!-- 文档元素 -->
<note>
    <to> Person1 </to>
    <from> Person2 </from>
    <head> XML </head>
    <body> This is XML Document </body>
</note>

这里 文档声明文档元素 都是很好理解的 , 与 超文本标记语言( HTML ) 是类似的 .

 XML和HTML虽然语言形式类似 , 但本质存在差异

 1. XML是HTML的补充 , 而不是用于替代HTML

 2. XML是为传输和存储数据而设计 , 其焦点在数据的内容上 . 而HTML是为显示数据而设计 , 其焦点在数据的外观上 . 简单的来说 , XML为传输数据 , HTML为显示数据

本章的重点也就是放在DTD上 , 也就是这个文档类型定义究竟是如何生成的 .


DTD (Document Type Definition)

DTD规定了文档的逻辑结构 , 它可以定义文档的语法 . 文档的语法反过来也可以让XML语法分析程序确认页面标记使用的合法性( 验证自身的数据 ) .

DTD定义了页面的元素 , 元素的属性 , 元素和属性之间的关系 . 元素和元素之间用起始标记和结束标记来定界 .

DTD不具强制性 , 可以使用预先定义的公共DTD , 也可以建立属于自己的DTD . 所以DTD可以直接在XML文档内声明 , 也可以外部引用


下面来谈一谈 DTD 中常用的关键词

关键词 含义
!DOCTYPE 声明一个DTD
!ELEMENT 在DTD中声明一个元素
!ATTLIST 在DTD中声明一个属性
!ENTITY 在DTD中声明一个实体

 

  1. !DOCTYPE
    • 当DTD被包含在XML源文件中时 可以通过下面语法来声明DTD
      <!DOCTYPE 根元素 [元素的声明]>

    • 当DTD位于XML源文件外部时 , 那么应当使用下面的语法结构来声明DTD
      <!DOCTYPE 根元素 SYSTEM "文件路径">

 

  1. !ELEMENT

    元素是 XML / HTML 文档的主要构建模块

    • 可以通过如下方式在DTD中声明一个XML元素
      <!ELEMENT 元素名称 元素类型>

      <!ELEMENT 元素名称 (元素内容)>

    • 可以使用EMPTY关键字声明一个空元素
      <!ELEMENT 元素名称 EMPTY>

    • 只有PCDATA的元素通过圆括号中的 #PCDATA关键字进行声明
      <!ELEMENT 元素名称 (#PCDATA)>

    • 通过类别关键字ANY来声明带有任何内容的元素
      <!ELEMENT 元素名称 ANY>

    • 多个子元素的元素可以通过在圆括号中的子元素名称进行声明
      <!ELEMENT 元素名称 ( 子元素名1 , 子元素名2 , 子元素名3 , ... )

      注意 , 当子元素以逗号分隔的序列的形式进行声明时 , 这些子元素必须以 相同的顺序 出现在文档中 
      
    • 声明只出现一次的子元素
      <!ELEMENT 元素名称 (子元素名称)>

       子元素必须出现且仅在父元素中出现一次
      
    • 声明至少出现一次的子元素
      <!ELEMENT 元素名称 (子元素名称+)>

       子元素必须出现且至少在父元素中出现一次
      
    • 声明出现零次或者多次的子元素
      <!ELEMENT 元素名称 (子元素名称*)>

    • 声明出现零次或者一次的子元素
      <!ELEMENT 元素名称 (子元素名称?)>

       子元素需要在父元素中出现零次或者一次
      
    • 声明 子元素A 或者 子元素B
      <!ELEMENT 元素名称 (子元素A | 子元素B)>

 

  1. !ATTLIST

    可以通过如下方式声明一个属性

    属性可提供有关元素的额外信息
    <!ATTLIST 元素名称 属性名称 属性类型 默认值>

    举个例子

     # DTD中声明
    <!ATTLIST text type CDATA "helloworld">
    
     # XML中引用
    <text type="helloworld" />
    

    属性类型参数选项

    png

    默认值参数选项

    png

 

  1. !Entity

    实体是用于定义引用普通文本或者特殊字符的快捷方式的变量

    实体引用是对实体的引用

    在XML中被预定义的实体引用与对应字符

    png

    实体可以在内部或者外部引用 , 引用资源有个好处是 : 对引用资源做的任何更改都会自动在文档中更新

    • 内部引用实体
      <!ENTITY 实体名称 "实体值">

    • 引用外部实体
      <!ENTITY 实体名称 SYSTEM "实体值" >

    参数实体

    事实上 , 实体也可以分成两个类别 : 通用实体参数实体

    通用实体都是通过 (& + 实体名称 + ;) 这种形式来调用的 . 这也是平时最常见的调用方法 , 在DTD中定义 , 在XML文档中引用

    # 例子
    # 在DTD中定义
    ... ...
    <!ENTITY happy "happyeveryday">
    ... ...
    
    # 在XML中调用
    <... ...> &happy; </... ...>
    

    参数实体的声明和调用都是通过百分号 (%) 来完成的 .

    参数实体仅能在DTD文件中被创建和被引用 , 而且参数实体在DTD中解析优先于XML内部实体

    参数实体和通用实体类似 , 可以引用内部参数实体 , 也可以引用外部参数实体

    举个例子

 # 引用内部参数实体
 <!ENTITY % 实体名称 "实体值">

 # 引用外部参数实体
 <!ENTITY % 实体名称 SYSTEM "实体值">

还有什么遗漏的 ?

  • PCDATA ( Parsed character data , 被解析的字符数据 )

    PCDATA中的数据是要给XML解析器解析的文本 . 这些文本将被XML解析器检查实体以及标记 . 文本中的标签会被当做标记来处理 , 实体将会被展开 .

    也就是说 , PCDATA中的数据不应该包含任何 & , < , > 字符 , 需要将他们替换为字符实体

  • CDATA ( Character data , 字符数据)

    CDATA 中的文本是不会被XML解析器解析的 . 这些文本那种的标签不会被当做标记来对大唐 , 其中的实体也不会被展开

    在XML元素中 , " < " 和 " & " 是非法的字符

     " < " 会产生错误 , 因为XML解析器会把它解释为新元素的开始
    
     " & " 会产生错误 , 因为XML解释器会把它解释为字符实体的开始
    

    因此 , 如果某文件包含大量的非法字符时( 比如JavaScript文件 ) , 可以将脚本代码写入到 CDATA 中

    CDATA部分由 <![CDATA[ 开始 , 由 ]]> 结束

    在CDATA中的文本可以存在 & , < , > 这些特殊字符

  • 举个例子

 # CDATA
 if (a > b){
    System.out.println("happy");
 }

  # PCDATA
  if (a   & gt ;   b){
    System.out.println("happy");
 }
最后修改日期:2019年9月17日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。