MIME 嗅探

Living Standard — 最后更新

参与:
GitHub whatwg/mimesniff (新建 issue, 打开的 issue)
Matrix 聊天
提交历史:
GitHub whatwg/mimesniff/commits
此提交的快照
@mimesniff
测试:
web-platform-tests mimesniff/ (进行中 工作)
翻译 (非规范性)
日本語
简体中文

摘要

MIME 嗅探标准定义了资源嗅探的规则。

1. 简介

HTTP Content-Type 头字段用于指示 HTTP 响应的 MIME 类型。 但许多 HTTP 服务器提供的 Content-Type 头字段值与实际响应内容并不匹配。 过去,Web 浏览器为兼容这些服务器,除了检查 Content-Type 头字段之外,还会检查 HTTP 响应内容,以确定实际的 MIME 类型。

没有明确规范如何 “嗅探(sniff)” MIME 类型,每个用户代理都被迫逆向工程其他用户代理的算法,以保持互操作性。 这种努力最终并不完全成功,导致了用户代理间行为的差异。 在某些情况下,这些差异带来了安全隐患,因为用户代理可能会将 HTTP 响应解释为与服务器预期不同的 MIME 类型。

当 “诚实” 服务器允许潜在恶意用户上传文件,并以低权限 MIME 类型提供这些文件内容时,安全问题最为严重。 例如,如果服务器认为客户端会将用户上传的文件视为图片(因此是良性的),但用户代理却将其视为 HTML(进而可能执行其中的脚本),攻击者就有可能窃取用户凭据并实施其他跨站脚本攻击。 (恶意服务器当然可以在 Content-Type 头字段中指定任意 MIME 类型。)

本文档描述了一种内容嗅探算法,在满足用户代理兼容性需求和现有 Web 内容的安全约束之间做出了平衡。 该算法起源于 Adam Barth、Juan Caballero 和 Dawn Song 的研究,基于主流用户代理的内容嗅探算法、现有 Web 内容的大型数据库以及在大量用户中部署所收集的度量数据。[SECCONTSNIFF]

2. 一致性要求

本文档中的关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHALL"、"SHALL NOT"、"SHOULD"、 "SHOULD NOT"、"RECOMMENDED"、"NOT RECOMMENDED"、"MAY" 和 "OPTIONAL",其含义应按 RFC 2119 所述理解。 为便于阅读,这些关键词通常不会全部大写。 [KEYWORDS]

作为算法一部分的命令式要求(如 "去除所有前导空格字符" 或 "返回 false 并终止这些步骤"),应结合引入算法时使用的关键词来理解其含义。

以算法或具体步骤表述的一致性要求可以通过任何方式实现,只要最终结果等价即可。 特别需要注意的是,本规范定义的算法旨在易于理解,并不以高性能为目标。

3. 术语

本规范依赖 Infra 标准。[INFRA]

一个 HTTP 令牌码点(HTTP token code point) 是 U+0021 (!)、U+0023 (#)、U+0024 ($)、U+0025 (%)、 U+0026 (&)、U+0027 (')、U+002A (*)、U+002B (+)、U+002D (-)、U+002E (.)、U+005E (^)、U+005F (_)、 U+0060 (`)、U+007C (|)、U+007E (~),或一个 ASCII 字母或数字

这与 token 产生式的值空间一致。 [HTTP-SEMANTICS]

一个 HTTP 引号字符串令牌码点(quoted-string token code point) 是 U+0009 TAB、范围 U+0020 SPACE 到 U+007E (~)(含)、或范围 U+0080 到 U+00FF (ÿ)(含)的码点

这与 quoted-string 产生式的有效值空间一致。定义上它是 HTTP 令牌码点 的超集。[HTTP-SEMANTICS]

一个 二进制数据字节(binary data byte)字节值在 0x00 到 0x08 (NUL 到 BS) 范围内,或 字节值为 0x0B (VT),或字节值在 0x0E 到 0x1A (SO 到 SUB) 范围内,或字节值在 0x1C 到 0x1F (FS 到 US) 范围内。

一个 空白字节(whitespace byte) (缩写为 0xWS)为下列任一 字节:0x09 (HT)、 0x0A (LF)、0x0C (FF)、0x0D (CR)、0x20 (SP)。

一个 标签终止字节(tag-terminating byte) (缩写为 0xTT)为下列任一 字节:0x20 (SP)、0x3E (">")。

本文中的数学运算符采用 [ENCODING] 中定义的符号。此外,按位非用 ~ 表示。

4. MIME 类型

4.1. MIME 类型表示

MIME 类型 表示 互联网媒体类型,定义见 Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types。也可称为 MIME 类型记录[MIMETYPE]

标准建议始终使用 MIME 类型 这个术语,以避免与 Media Queries 中的 媒体类型 混淆。[MEDIAQUERIES]

MIME 类型主类型(type) 是非空 ASCII 字符串

MIME 类型子类型(subtype) 是非空 ASCII 字符串

MIME 类型参数(parameters) 是一个 有序映射(ordered map),其 ASCII 字符串为仅包含 HTTP 引号字符串令牌码点字符串。初始为空。

4.2. MIME 类型杂项

MIME 类型 mimeType本质(essence)mimeTypetype,加上 U+002F (/) 和 subtype

MIME 类型 被用户代理支持,指用户代理能够解析该 MIME 类型资源并将其展示给用户。

理想情况应更精确。参见 w3c/preload #113

最简化受支持的 MIME 类型,给定 MIME 类型 mimeType,执行如下步骤,返回 ASCII 字符串

  1. 如果 mimeTypeJavaScript MIME 类型,则返回 "text/javascript"。

  2. 如果 mimeTypeJSON MIME 类型,则返回 "application/json"。

  3. 如果 mimeType本质为 "image/svg+xml",则返回 "image/svg+xml"。

    SVG 区别于其他 XML MIME 类型

  4. 如果 mimeTypeXML MIME 类型,则返回 "application/xml"。

  5. 如果 mimeType 被用户代理支持,则返回 mimeType本质

  6. 返回空字符串。

本算法目的是让调用者区分具有不同处理模型的 MIME 类型(如 GIF 和 PNG),但除此之外尽量少暴露信息。

4.3. MIME 类型写入

有效 MIME 类型字符串 指符合 media-type 产生式的字符串。特别地,有效 MIME 类型字符串可包含 参数[HTTP-SEMANTICS]

有效 MIME 类型字符串主要供一致性检查器使用。

"text/html" 是 有效 MIME 类型字符串

"text/html;" 不是 有效 MIME 类型字符串,但 解析 MIME 类型仍会返回一个与输入为 "text/html" 时相同的MIME 类型记录

无参数有效 MIME 类型字符串是 不包含 U+003B (;) 的 有效 MIME 类型字符串

4.4. 解析 MIME 类型

解析 MIME 类型,给定字符串 input,执行如下步骤:

  1. 去除 input 的前后 HTTP 空白字符

  2. positioninput位置变量,初始指向 input 开头。

  3. type收集一串不是 U+002F (/) 的码点所得结果,输入为 inputposition

  4. 如果 type 为空字符串或不只包含 HTTP 令牌码点,则返回失败。

  5. 如果 position 已超出 input 末尾,则返回失败。

  6. position 前进 1。(跳过 U+002F (/)。)

  7. subtype收集一串不是 U+003B (;) 的码点所得结果,输入为 inputposition

  8. 去除 subtype 尾部的 HTTP 空白字符

  9. 如果 subtype 为空字符串或不只包含 HTTP 令牌码点,则返回失败。

  10. mimeType 为新建的 MIME 类型记录,其 typetype(转为 ASCII 小写), subtypesubtype(转为 ASCII 小写)。

  11. position 未超出 input 末尾时:

    1. position 前进 1。(跳过 U+003B (;)。)

    2. 收集一段码点序列 ,这些码点是HTTP 空白符,从 inputposition 开始。

      效果类似 跳过 ASCII 空白,但用 HTTP 空白字符 而不是 ASCII 空白

    3. parameterName收集一串不是 U+003B (;) 或 U+003D (=) 的码点所得结果,输入为 inputposition

    4. parameterName 转为 ASCII 小写

    5. 如果 position 未超出 input 末尾,则:

      1. 如果 inputposition码点是 U+003B (;),则 继续

      2. position 前进 1。(跳过 U+003D (=)。)

    6. 如果 position 已超出 input 末尾,则 中断

    7. parameterValue 为 null。

    8. 如果 inputposition码点为 U+0022 ("),则:

      1. parameterValue 设为 收集 HTTP 引号字符串(输入:inputposition、true)结果。

      2. 收集一串不是 U+003B (;) 的码点(输入:inputposition)。

        输入 text/html;charset="shift_jis"iso-2022-jp,结果为 text/html;charset=shift_jis

    9. 否则:

      1. parameterValue 设为 收集一串不是 U+003B (;) 的码点所得结果(输入:inputposition)。

      2. 去除 parameterValue 尾部 HTTP 空白字符

      3. 如果 parameterValue 为空字符串,则 继续

    10. 若全部满足:

      设置 mimeType参数[parameterName] 为 parameterValue

  12. 返回 mimeType


从字节解析 MIME 类型,给定 字节序列 input,执行如下步骤:

  1. stringinput 同构解码后的结果。

  2. 返回 解析 MIME 类型string)的结果。

4.5. 序列化 MIME 类型

序列化 MIME 类型,给定 MIME 类型 mimeType,执行如下步骤:

  1. serializationmimeType主类型、U+002F (/) 以及 mimeType子类型 的拼接结果。

  2. 对于 mimeType 的每个 参数 namevalue

    1. serialization 后添加 U+003B (;)。

    2. serialization 后添加 name

    3. serialization 后添加 U+003D (=)。

    4. 如果 value 不仅包含 HTTP 令牌码点,或 value 为空字符串,则:

      1. value 中每个 U+0022 (") 或 U+005C (\) 前加 U+005C (\)。

      2. value 前添加 U+0022 (")。

      3. value 后添加 U+0022 (")。

    5. value 添加到 serialization

  3. 返回 serialization


将 MIME 类型序列化为字节,给定 MIME 类型 mimeType,执行如下步骤:

  1. stringSerialization序列化 MIME 类型mimeType)的结果。

  2. 返回 stringSerialization 同构编码后的结果。

4.6. MIME 类型分组

图像 MIME 类型(image MIME type)MIME 类型主类型为 "image"。

音频或视频 MIME 类型(audio or video MIME type)MIME 类型主类型为 "audio" 或 "video",或 本质为 "application/ogg"。

字体 MIME 类型(font MIME type)MIME 类型主类型为 "font",或 本质为下列之一:[RFC8081]

基于 ZIP 的 MIME 类型(ZIP-based MIME type)MIME 类型子类型以 "+zip" 结尾,或 本质为下列之一:

归档 MIME 类型(archive MIME type)MIME 类型本质为下列之一:

XML MIME 类型MIME 类型子类型以 "+xml" 结尾,或 本质为 "text/xml" 或 "application/xml"。[RFC7303]

HTML MIME 类型MIME 类型本质为 "text/html"。

可脚本 MIME 类型(scriptable MIME type)XML MIME 类型HTML MIME 类型,或 MIME 类型本质为 "application/pdf"。

JavaScript MIME 类型MIME 类型本质为下列之一:

字符串JavaScript MIME 类型本质匹配(essence match),如果它与某个 ASCII 不区分大小写JavaScript MIME 类型本质字符串一致。

此钩子用于 type 属性和 script 元素。[HTML]

JSON MIME 类型MIME 类型子类型以 "+json" 结尾,或 本质为 "application/json" 或 "text/json"。

5. 资源处理

资源是……

对于每个要处理的资源,用户代理必须跟踪以下相关元数据:

5.1. 资源元数据解释

资源提供的 MIME 类型由与该资源相关的外部来源提供。获取该信息的方法取决于资源的获取方式。

为了确定资源提供的 MIME 类型,用户代理必须使用以下提供的 MIME 类型检测算法

  1. supplied-type 为 null。
  2. 如果资源是通过 HTTP 获取的,执行以下步骤:
    1. 如果该资源有一个或多个 Content-Type 头,执行以下步骤:
      1. supplied-type 设为与该资源关联的最后一个 Content-Type 头的值。

        通过 HTTP 获取的资源,其提供的 MIME 类型不依赖于文件扩展名,因为扩展名不可靠且容易伪造。

      2. 如果 supplied-type 完全等于下表中的某个值,则设置检查 Apache bug 标志
        十六进制字节 ASCII 字节
        74 65 78 74 2F 70 6C 61 69 6E text/plain
        74 65 78 74 2F 70 6C 61 69 6E
        3B 20 63 68 61 72 73 65 74 3D
        49 53 4F 2D 38 38 35 39 2D 31
        text/plain; charset=ISO-8859-1
        74 65 78 74 2F 70 6C 61 69 6E
        3B 20 63 68 61 72 73 65 74 3D
        69 73 6F 2D 38 38 35 39 2D 31
        text/plain; charset=iso-8859-1
        74 65 78 74 2F 70 6C 61 69 6E
        3B 20 63 68 61 72 73 65 74 3D
        55 54 46 2D 38
        text/plain; charset=UTF-8

        提供的 MIME 类型检测算法检测这些精确的字节序列,是因为一些较老版本的 Apache 存在一个 bug,导致其在提供未知MIME 类型文件时返回这些 Content-Type 头。

    [HTTP-SEMANTICS]

  3. 如果资源是直接从文件系统获取的,令 supplied-type 为文件系统提供的MIME 类型
  4. 如果资源是通过其他协议(如 FTP)获取的,令 supplied-type 为该协议判定的MIME 类型(若有)。

    [FTP]

  5. 如果 supplied-type 不是MIME 类型,则提供的 MIME 类型未定义。

    终止这些步骤。

  6. 提供的 MIME 类型supplied-type

5.2. 读取资源头部

资源头部字节序列,即资源开头的部分,由读取资源头部确定。

读取资源头部,执行如下步骤:

  1. buffer 为一个字节序列
  2. 资源中读取字节buffer,直到满足下列任一条件:
    • 到达资源末尾。
    • buffer中的字节数大于等于 1445。
    • 用户代理认定已过了合理的时间。

    如果 buffer字节数大于等于 1445,则MIME 类型嗅探算法在绝大多数情况下是确定性的。

    但某些因素(如网络慢)可能导致用户代理无法在合理时间内读取到 1445 字节

  3. 资源头部buffer

资源头部每个资源只需确定一次。

6. 匹配 MIME 类型模式

字节模式(byte pattern)是用于模式匹配算法比对的字节序列

模式掩码(pattern mask)是用于确定与字节模式比对时哪些字节有意义的字节序列,用于模式匹配算法

模式掩码中,0xFF 表示该字节严格有意义,0xDF 表示该字节以 ASCII 不区分大小写方式有意义,0x00 表示该字节无意义。

要判断一个字节序列是否匹配特定的字节模式,请使用如下模式匹配算法。该算法接收一个字节序列 input、一个字节模式 pattern、一个模式掩码 mask,以及一个要忽略的字节集合 ignored,返回 true 或 false。

  1. 断言:pattern长度等于 mask长度

  2. 如果 input长度小于 pattern长度,返回 false。

  3. s = 0。

  4. s < input长度

    1. 如果 ignored包含 input[s],中断

    2. s = s + 1。

  5. p = 0。

  6. p < pattern长度

    1. maskedDatainput[s] 和 mask[p] 进行按位与的结果。

    2. 如果 maskedData 不等于 pattern[p],返回 false。

    3. s = s + 1。

    4. p = p + 1。

  7. 返回 true。

6.1. 匹配图像类型模式

要确定字节模式 图像 MIME 类型的哪一项与 字节序列 input 匹配(如有),请使用如下图像类型模式匹配算法

  1. 对下表每一行 row 执行如下步骤:

    1. patternMatched模式匹配算法(参数:input、行首列、行次列、行第三列)的结果。

    2. 如果 patternMatched 为 true,则返回 row 的第四列值。

    字节模式 模式掩码 要忽略的前导字节 图像 MIME 类型 说明
    00 00 01 00 FF FF FF FF image/x-icon Windows Icon 签名。
    00 00 02 00 FF FF FF FF image/x-icon Windows Cursor 签名。
    42 4D FF FF image/bmp 字符串 "BM",BMP 签名。
    47 49 46 38 37 61 FF FF FF FF FF FF image/gif 字符串 "GIF87a",GIF 签名。
    47 49 46 38 39 61 FF FF FF FF FF FF image/gif 字符串 "GIF89a",GIF 签名。
    52 49 46 46 00 00 00 00 57 45 42 50 56 50 FF FF FF FF 00 00 00 00 FF FF FF FF FF FF image/webp 字符串 "RIFF" 后四个字节,再加 "WEBPVP"。
    89 50 4E 47 0D 0A 1A 0A FF FF FF FF FF FF FF FF image/png 一个校验字节后跟 "PNG",再跟 CR LF SUB LF,为 PNG 签名。
    FF D8 FF FF FF FF image/jpeg JPEG 起始标记及另一个标记的指示字节
  2. 返回 undefined。

6.2. 匹配音频或视频类型模式

要确定字节模式 音频或视频 MIME 类型的哪一项与 字节序列 input 匹配(如有),请使用如下音频或视频类型模式匹配算法

  1. 对下表每一行 row 执行如下步骤:

    1. patternMatched模式匹配算法(参数:input、行首列、行次列、行第三列)的结果。

    2. 如果 patternMatched 为 true,则返回 row 的第四列值。

    字节模式 模式掩码 要忽略的前导字节 音频或视频 MIME 类型 说明
    46 4F 52 4D 00 00 00 00 41 49 46 46 FF FF FF FF 00 00 00 00 FF FF FF FF audio/aiff 字符串 "FORM" 后四个字节,再加 "AIFF",即 AIFF 签名。
    49 44 33 FF FF FF audio/mpeg 字符串 "ID3",ID3v2 标记的 MP3 签名。
    4F 67 67 53 00 FF FF FF FF FF application/ogg 字符串 "OggS" 后跟 NUL,即 Ogg 容器签名。
    4D 54 68 64 00 00 00 06 FF FF FF FF FF FF FF FF audio/midi 字符串 "MThd" 后跟四个表示数字 6(32 位大端)的字节,即 MIDI 签名。
    52 49 46 46 00 00 00 00 41 56 49 20 FF FF FF FF 00 00 00 00 FF FF FF FF video/avi 字符串 "RIFF" 后四个字节,再加 "AVI ",即 AVI 签名。
    52 49 46 46 00 00 00 00 57 41 56 45 FF FF FF FF 00 00 00 00 FF FF FF FF audio/wave 字符串 "RIFF" 后四个字节,再加 "WAVE",即 WAVE 签名。
  2. 如果 input 匹配 MP4 签名,返回 "video/mp4"。

  3. 如果 input 匹配 WebM 签名,返回 "video/webm"。

  4. 如果 input 匹配无 ID3 的 MP3 签名,返回 "audio/mpeg"。

  5. 返回 undefined。

6.2.1. MP4 签名

要判断一个字节序列是否匹配 MP4 签名,使用以下步骤:

  1. sequence 为要匹配的字节序列sequence[s] 表示第 s字节sequence[0] 为第一个字节。
  2. lengthsequence字节数。
  3. 如果 length 小于 12,返回 false。
  4. box-sizesequence[0] 到 sequence[3] 四个字节,按大端解释为 32 位无符号整数。
  5. 如果 length 小于 box-sizebox-size 模 4 不为 0,返回 false。
  6. 如果 sequence[4] 到 sequence[7] 四个字节不等于 0x66 0x74 0x79 0x70(ftyp),返回 false。
  7. 如果 sequence[8] 到 sequence[10] 三个字节等于 0x6D 0x70 0x34(mp4),返回 true。
  8. bytes-read 为 16。

    这忽略了 “major brand” 版本号对应的四个字节。

  9. bytes-read 小于 box-size 时,循环执行:
    1. 如果 sequence[bytes-read] 到 sequence[bytes-read + 2] 三个字节为 0x6D 0x70 0x34(mp4),返回 true。
    2. bytes-read 增加 4。
  10. 返回 false。

6.2.2. WebM 签名

要判断一个字节序列是否匹配 WebM 签名,使用以下步骤:

  1. sequence 为要匹配的字节序列sequence[s] 表示第 s字节sequence[0] 为第一个字节。
  2. lengthsequence字节数。
  3. 如果 length 小于 4,返回 false。
  4. 如果 sequence[0] 到 sequence[3] 四个字节不等于 0x1A 0x45 0xDF 0xA3,返回 false。
  5. iter 为 4。
  6. iter 小于 lengthiter 小于 38 时,循环执行:
    1. 如果 sequence[iter] 和 sequence[iter+1] 两个字节等于 0x42 0x82,
      1. iter 增加 2。
      2. 如果 iter 大于等于 length,终止这些步骤。
      3. number size解析 vintsequence[iter] 得到的结果。
      4. iter 增加 number size
      5. 如果 iter 大于等于 length - 4,终止这些步骤。
      6. matched匹配填充序列 0x77 0x65 0x62 0x6D(webm)在 sequenceiter 处的结果。
      7. 如果 matched 为 true,终止并返回 true。
    2. iter 增加 1。
  7. 返回 false。

解析 vint,在 字节序列 sequence、长度 length、起始索引 iter 上,执行:

  1. mask = 128。
  2. max vint length = 8。
  3. number size = 1。
  4. index = 0。
  5. number size 小于 max vint length 且小于 length 时,循环:
    1. 如果 sequence[index] & mask 不为零,终止循环。
    2. mask 右移一位。
    3. number size 增加 1。
  6. parsed number = sequence[index] & ~mask
  7. index 增加 1。
  8. bytes remaining = number size - 1。
  9. bytes remaining 不为零时,循环:
    1. parsed number 左移 8。
    2. parsed number |= sequence[index]。
    3. index 增加 1。
    4. 如果 index 大于等于 length,终止循环。
    5. bytes remaining 减 1。
  10. 返回 parsed numbernumber size

匹配填充序列 pattern 在序列 sequence 偏移 offsetend,当且仅当 sequence 长度大于 end,且区间 [offset, end] 的字节与 pattern 完全一致(前面可有若干 0x00),否则返回 false。

6.2.3. 无 ID3 的 MP3 签名

要判断一个字节序列是否匹配无 ID3 的 MP3 签名,使用以下步骤:

  1. sequence 为要匹配的字节序列sequence[s] 表示第 s字节sequence[0] 为第一个字节。
  2. lengthsequence字节数。
  3. 初始化 s 为 0。
  4. 如果 匹配 mp3 头 返回 false,返回 false。
  5. sequences 偏移上解析 mp3 帧
  6. skipped-bytes计算 mp3 帧大小的返回值。
  7. 如果 skipped-bytes 小于 4,或 skipped-bytes 大于 s - length,返回 false。
  8. s 增加 skipped-bytes
  9. 如果 匹配 mp3 头 返回 false,则返回 false,否则返回 true。

匹配 mp3 头,使用长度为 length字节序列 sequence 在偏移 s 上:

  1. length 小于 4,返回 false。
  2. sequence[s] 不等于 0xff 且 sequence[s + 1] & 0xe0 不等于 0xe0,返回 false。
  3. layer = (sequence[s+1] & 0x06) >> 1。
  4. layer 为 0,返回 false。
  5. bit-rate = (sequence[s+2] & 0xf0) >> 4。
  6. bit-rate 为 15,返回 false。
  7. sample-rate = (sequence[s+2] & 0x0c) >> 2。
  8. sample-rate 为 3,返回 false。
  9. freqsample-rate 在 sample-rate 表中的值。
  10. final-layer = 4 - (sequence[s+1])。
  11. 若 (final-layer & 0x06) >> 1 不为 3,返回 false。
  12. 返回 true。

计算 mp3 帧大小,执行如下:

  1. version 为 1,则 scale = 72,否则 scale = 144。
  2. size = bitrate * scale / freq
  3. pad 不为零,则 size 增加 1。
  4. 返回 size

解析 mp3 帧,执行如下:

  1. version = (sequence[s + 1] & 0x18) >> 3。
  2. bitrate-index = (sequence[s + 2] & 0xf0) >> 4。
  3. version & 0x01 非零,则 bitrate 取 mp2.5-rates 表中 bitrate-index 的值。
  4. version & 0x01 为零,则 bitrate 取 mp3-rates 表中 bitrate-index 的值。
  5. samplerate-index = (sequence[s + 2] & 0x0c) >> 2。
  6. samplerate 为 sample-rate 表中 samplerate-index 的值。
  7. pad = (sequence[s + 2] & 0x02) >> 1。
mp3-rates 表
索引 mp3-rates
0 0
1 32000
2 40000
3 48000
4 56000
5 64000
6 80000
7 96000
8 112000
9 128000
10 160000
11 192000
12 224000
13 256000
14 320000
mp2.5-rates 表
索引 mp2.5-rates
0 0
1 8000
2 16000
3 24000
4 32000
5 40000
6 48000
7 56000
8 64000
9 80000
10 96000
11 112000
12 128000
13 144000
14 160000
sample-rate 表
索引 采样率
0 44100
1 48000
2 32000

6.3. 匹配字体类型模式

要确定字体 MIME 类型的哪一个字节模式字节序列 input 匹配(如有),请使用如下字体类型模式匹配算法

  1. 对下表每一行 row 执行如下步骤:

    1. patternMatched模式匹配算法(参数:input、行首列、行次列、行第三列)的结果。

    2. 如果 patternMatched 为 true,则返回 row 的第四列值。

    字节模式 模式掩码 要忽略的前导字节 字体 MIME 类型 说明
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4C 50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF application/vnd.ms-fontobject 34 个字节后跟字符串 "LP",即 Embedded OpenType 签名。
    00 01 00 00 FF FF FF FF font/ttf 4 个字节表示版本号 1.0,TrueType 签名。
    4F 54 54 4F FF FF FF FF font/otf 字符串 "OTTO",OpenType 签名。
    74 74 63 66 FF FF FF FF font/collection 字符串 "ttcf",TrueType Collection 签名。
    77 4F 46 46 FF FF FF FF font/woff 字符串 "wOFF",Web Open Font Format 1.0 签名。
    77 4F 46 32 FF FF FF FF font/woff2 字符串 "wOF2",Web Open Font Format 2.0 签名。
  2. 返回 undefined。

6.4. 匹配归档类型模式

要确定归档 MIME 类型的哪一个字节模式字节序列 input 匹配(如有),请使用如下归档类型模式匹配算法

  1. 对下表每一行 row 执行如下步骤:

    1. patternMatched模式匹配算法(参数:input、行首列、行次列、行第三列)的结果。

    2. 如果 patternMatched 为 true,则返回 row 的第四列值。

    字节模式 模式掩码 要忽略的前导字节 归档 MIME 类型 说明
    1F 8B 08 FF FF FF application/x-gzip GZIP 归档签名。
    50 4B 03 04 FF FF FF FF application/zip 字符串 "PK" 后跟 ETX EOT,为 ZIP 归档签名。
    52 61 72 20 1A 07 00 FF FF FF FF FF FF FF application/x-rar-compressed 字符串 "Rar " 后跟 SUB BEL NUL,为 RAR 归档签名。
  2. 返回 undefined。

7. 确定资源的计算 MIME 类型

要确定资源计算出的 MIME 类型,用户代理必须使用如下MIME 类型嗅探算法

  1. 如果提供的 MIME 类型XML MIME 类型HTML MIME 类型,则计算出的 MIME 类型提供的 MIME 类型

    终止这些步骤。

  2. 如果提供的 MIME 类型未定义,或其本质为 "unknown/unknown"、"application/unknown" 或 "*/*",则以 sniff-scriptable 标志no-sniff 标志的相反值,执行未知 MIME 类型识别规则,并终止这些步骤。
  3. 如果no-sniff 标志已设置,则计算出的 MIME 类型提供的 MIME 类型

    终止这些步骤。

  4. 如果检查 Apache bug 标志已设置,执行文本或二进制资源判断规则,并终止这些步骤。
  5. 如果提供的 MIME 类型被用户代理支持的图像 MIME 类型,则令 matched-type 为使用图像类型模式匹配算法,以资源头部为待匹配字节序列的结果。
  6. 如果 matched-type 不为 undefined,计算出的 MIME 类型matched-type

    终止这些步骤。

  7. 如果提供的 MIME 类型被用户代理支持的音频或视频 MIME 类型,则令 matched-type 为使用音频或视频类型模式匹配算法,以资源头部为待匹配字节序列的结果。
  8. 如果 matched-type 不为 undefined,计算出的 MIME 类型matched-type

    终止这些步骤。

  9. 计算出的 MIME 类型提供的 MIME 类型

7.1. 识别未知 MIME 类型的资源

sniff-scriptable 标志用于未知 MIME 类型识别规则,判断是否需要嗅探可脚本 MIME 类型

如果调用未知 MIME 类型识别规则时未指定 sniff-scriptable 标志,则其默认未设置。

要确定未知MIME 类型资源 resource计算出的 MIME 类型,执行如下未知 MIME 类型识别规则

  1. 如果 sniff-scriptable 标志已设置,对下表每一行 row 执行:

    1. patternMatched模式匹配算法(参数:resource资源头部、行首列、行次列、行第三列)的结果。

    2. 如果 patternMatched 为 true,返回 row 的第四列值。

    字节模式 模式掩码 要忽略的前导字节 计算出的 MIME 类型 说明
    3C 21 44 4F 43 54 59 50 45 20 48 54 4D 4C TT FF FF DF DF DF DF DF DF DF FF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<!DOCTYPE HTML" 后跟标签终止字节
    3C 48 54 4D 4C TT FF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<HTML" 后跟标签终止字节
    3C 48 45 41 44 TT FF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<HEAD" 后跟标签终止字节
    3C 53 43 52 49 50 54 TT FF DF DF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<SCRIPT" 后跟标签终止字节
    3C 49 46 52 41 4D 45 TT FF DF DF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<IFRAME" 后跟标签终止字节
    3C 48 31 TT FF DF FF FF 空白字节 text/html 不区分大小写的字符串 "<H1" 后跟标签终止字节
    3C 44 49 56 TT FF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<DIV" 后跟标签终止字节
    3C 46 4F 4E 54 TT FF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<FONT" 后跟标签终止字节
    3C 54 41 42 4C 45 TT FF DF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<TABLE" 后跟标签终止字节
    3C 41 TT FF DF FF 空白字节 text/html 不区分大小写的字符串 "<A" 后跟标签终止字节
    3C 53 54 59 4C 45 TT FF DF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<STYLE" 后跟标签终止字节
    3C 54 49 54 4C 45 TT FF DF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<TITLE" 后跟标签终止字节
    3C 42 TT FF DF FF 空白字节 text/html 不区分大小写的字符串 "<B" 后跟标签终止字节
    3C 42 4F 44 59 TT FF DF DF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<BODY" 后跟标签终止字节
    3C 42 52 TT FF DF DF FF 空白字节 text/html 不区分大小写的字符串 "<BR" 后跟标签终止字节
    3C 50 TT FF DF FF 空白字节 text/html 不区分大小写的字符串 "<P" 后跟标签终止字节
    3C 21 2D 2D TT FF FF FF FF FF 空白字节 text/html 字符串 "<!--" 后跟标签终止字节
    3C 3F 78 6D 6C FF FF FF FF FF 空白字节 text/xml 字符串 "<?xml"。
    25 50 44 46 2D FF FF FF FF FF application/pdf 字符串 "%PDF-",PDF 签名。
  2. 对下表每一行 row 执行:

    1. patternMatched模式匹配算法(参数:resource资源头部、行首列、行次列、行第三列)的结果。

    2. 如果 patternMatched 为 true,返回 row 的第四列值。

    字节模式 模式掩码 要忽略的前导字节 计算出的 MIME 类型 说明
    25 21 50 53 2D 41 64 6F 62 65 2D FF FF FF FF FF FF FF FF FF FF FF application/postscript 字符串 "%!PS-Adobe-",PostScript 签名。
    FE FF 00 00 FF FF 00 00 text/plain UTF-16BE BOM
    FF FE 00 00 FF FF 00 00 text/plain UTF-16LE BOM
    EF BB BF 00 FF FF FF 00 text/plain UTF-8 BOM

    用户代理可以隐式扩展此表以支持额外的MIME 类型

    但用户代理不应隐式扩展此表为任何已在表中的计算出的 MIME 类型增加新的字节模式,以避免权限提升漏洞。

    用户代理在扩展该表时不得引入权限提升漏洞。

  3. matchedType 为使用图像类型模式匹配算法,以 resource资源头部为参数的结果。

  4. 如果 matchedType 不为 undefined,返回 matchedType

  5. matchedType 为使用音频或视频类型模式匹配算法,以 resource资源头部为参数的结果。

  6. 如果 matchedType 不为 undefined,返回 matchedType

  7. matchedType 为使用归档类型模式匹配算法,以 resource资源头部为参数的结果。

  8. 如果 matchedType 不为 undefined,返回 matchedType

  9. 如果 resource资源头部不包含任何二进制数据字节,返回 "text/plain"。

  10. 返回 "application/octet-stream"。

7.2. 嗅探标签错误的二进制资源

要判断一个二进制资源是否被错误标记为纯文本,执行如下文本或二进制资源判断规则

  1. length资源头部中的字节数。
  2. 如果 length 大于等于 2 且前 2 个字节为 0xFE 0xFF(UTF-16BE BOM)或 0xFF 0xFE(UTF-16LE BOM),则计算出的 MIME 类型为 "text/plain"。

    终止这些步骤。

  3. 如果 length 大于等于 3 且前 3 个字节为 0xEF 0xBB 0xBF(UTF-8 BOM),则计算出的 MIME 类型为 "text/plain"。

    终止这些步骤。

  4. 如果资源头部不包含任何二进制数据字节,则计算出的 MIME 类型为 "text/plain"。

    终止这些步骤。

  5. 计算出的 MIME 类型为 "application/octet-stream"。

    必须确保文本或二进制资源判断规则永远不会将计算出的 MIME 类型判定为可脚本 MIME 类型,否则可能带来权限提升攻击。

8. 上下文相关嗅探

上下文是……

在某些上下文中,仅识别属于特定MIME 类型子集的资源才有意义。

在这种上下文中,适合使用上下文相关嗅探算法,代替MIME 类型嗅探算法,以确定计算出的 MIME 类型

上下文相关嗅探算法仅在资源为某一特定上下文相关的MIME 类型时,确定该资源计算出的 MIME 类型

8.1. 浏览上下文中的嗅探

使用MIME 类型嗅探算法

8.2. 图像上下文中的嗅探

要确定带有图像 MIME 类型资源计算出的 MIME 类型,执行如下专门针对图像嗅探的规则

  1. 如果提供的 MIME 类型XML MIME 类型,则计算出的 MIME 类型提供的 MIME 类型

    终止这些步骤。

  2. image-type-matched 为使用图像类型模式匹配算法,以资源头部为待匹配字节序列的结果。
  3. 如果 image-type-matched 不为 undefined,计算出的 MIME 类型image-type-matched

    终止这些步骤。

  4. 计算出的 MIME 类型提供的 MIME 类型

8.3. 音频或视频上下文中的嗅探

要确定具有音频或视频 MIME 类型资源计算出的 MIME 类型,执行如下专门针对音频和视频嗅探的规则

  1. 如果提供的 MIME 类型XML MIME 类型,则计算出的 MIME 类型提供的 MIME 类型

    终止这些步骤。

  2. audio-or-video-type-matched 为使用音频或视频类型模式匹配算法,以资源头部为待匹配字节序列的结果。
  3. 如果 audio-or-video-type-matched 不为 undefined,计算出的 MIME 类型audio-or-video-type-matched

    终止这些步骤。

  4. 计算出的 MIME 类型提供的 MIME 类型

8.4. 插件上下文中的嗅探

要确定在插件上下文中获取资源计算出的 MIME 类型,执行如下插件上下文嗅探规则

  1. 如果提供的 MIME 类型未定义,计算出的 MIME 类型为 "application/octet-stream"。
  2. 计算出的 MIME 类型提供的 MIME 类型

8.5. 样式上下文中的嗅探

要确定在样式上下文中获取资源计算出的 MIME 类型,执行如下样式上下文嗅探规则

  1. 如果提供的 MIME 类型未定义,……
  2. 计算出的 MIME 类型提供的 MIME 类型

8.6. 脚本上下文中的嗅探

要确定在脚本上下文中获取资源计算出的 MIME 类型,执行如下脚本上下文嗅探规则

  1. 如果提供的 MIME 类型未定义,……
  2. 计算出的 MIME 类型提供的 MIME 类型

8.7. 字体上下文中的嗅探

要确定具有字体 MIME 类型资源计算出的 MIME 类型,执行如下专门针对字体嗅探的规则

  1. 如果提供的 MIME 类型XML MIME 类型,则计算出的 MIME 类型提供的 MIME 类型

    终止这些步骤。

  2. font-type-matched 为使用字体类型模式匹配算法,以资源头部为待匹配字节序列的结果。
  3. 如果 font-type-matched 不为 undefined,计算出的 MIME 类型font-type-matched

    终止这些步骤。

  4. 计算出的 MIME 类型提供的 MIME 类型

8.8. 文本轨道上下文中的嗅探

计算出的 MIME 类型为 "text/vtt"。

8.9. 缓存清单上下文中的嗅探

计算出的 MIME 类型为 "text/cache-manifest"。

致谢

特别感谢 Adam Barth 和 Ian Hickson 维护了本规范的早期版本。

还要感谢 Alfred Hönes、 Andreu Botella、 Anne van Kesteren、 Ben Eidson、 Boris Zbarsky、 Darien Maillet Valentine、 David Singer、 Domenic Denicola、 Henri Sivonen、 Jean-Yves Avenard、 Jonathan Neal、 Joshua Cranmer、 Larry Masinter、 罗泽轩、 Mariko Kosaka、 Mark Pilgrim、 Paul Adenot、 Peter Occil、 Rob Buis、 Russ Cox、 Simon Pieters 以及 triple-underscore ,感谢他们的重要贡献。

本标准由 Gordon P. Hemsleyme@gphemsley.org)撰写。

知识产权声明

Copyright © WHATWG(Apple、Google、Mozilla、Microsoft)。本作品采用 知识共享署名 4.0 国际许可证 许可。若本规范部分内容被整合进源代码,则该部分源代码按 BSD 3-Clause License 许可。

本规范是 Living Standard。如需专利审核版本,请参见 Living Standard Review Draft

索引

本规范定义的术语

引用文献中定义的术语

参考文献

规范性引用

[ENCODING]
Anne van Kesteren. 编码标准(Encoding Standard). Living Standard. URL: https://encoding.spec.whatwg.org/
[FETCH]
Anne van Kesteren. Fetch 标准. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTTP-SEMANTICS]
R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. HTTP 语义(HTTP Semantics). 2022年6月. Internet Standard. URL: https://httpwg.org/specs/rfc9110.html
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. Living Standard. URL: https://infra.spec.whatwg.org/
[KEYWORDS]
S. Bradner. 在RFC中用于指示需求级别的关键词. 1997年3月. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[MIMETYPE]
N. Freed; N. Borenstein. 多用途互联网邮件扩展(MIME)第二部分:媒体类型. 1996年11月. Draft Standard. URL: https://www.rfc-editor.org/rfc/rfc2046

资料性引用

[FTP]
J. Postel; J. Reynolds. 文件传输协议(File Transfer Protocol). 1985年10月. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc959
[HTML]
Anne van Kesteren; 等. HTML 标准. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[MEDIAQUERIES]
Florian Rivoal; Tab Atkins Jr.. 媒体查询 4(Media Queries Level 4). URL: https://drafts.csswg.org/mediaqueries-4/
[RFC7303]
H. Thompson; C. Lilley. XML 媒体类型. 2014年7月. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc7303
[RFC8081]
C. Lilley. “font” 顶级媒体类型. 2017年2月. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc8081
[SECCONTSNIFF]
Adam Barth; Juan Caballero; Dawn Song. Web 浏览器的安全内容嗅探,或如何阻止论文自评(Secure Content Sniffing for Web Browsers, or How to Stop Papers from Reviewing Themselves). 2009年5月. URL: https://www.adambarth.com/papers/2009/barth-caballero-song.pdf