可验证凭证渲染方法 v1.0

W3C 工作草案

关于本文档的更多详细信息
此版本:
https://www.w3.org/TR/2026/WD-vc-render-method-20261013/
最新发布版本:
https://www.w3.org/TR/vc-render-method/
最新编辑者草案:
https://w3c.github.io/vc-render-method/
历史记录:
https://www.w3.org/standards/history/vc-render-method/
提交历史
编辑者:
Dmitri Zagidulin (MIT 数字凭证 联盟)
Manu Sporny (Digital Bazaar)
Patrick St. Louis (Open Security and Identity)
Isaac KOH (新加坡资讯通信媒体发展局)
作者:
Manu Sporny (Digital Bazaar)
Dmitri Zagidulin (MIT 数字凭证 联盟)
Calvin Cheng (新加坡政府科技局)
Kyle Huang Junyuan (新加坡政府 科技局)
Patrick St. Louis (Open Security and Identity)
反馈:
GitHub w3c/vc-render-method (拉取请求, 新问题, 未解决的问题)

摘要

本规范描述了可验证凭证数据模型的一种扩展机制,该机制可用于通过 视觉、听觉或触觉媒介来表示可验证凭证。它涵盖了 将可验证凭证渲染到实体文档、数字图像、 屏幕阅读器或盲文输出。

本文档的状态

本节描述本文档在发布时的状态。 当前 W3C 出版物列表以及本技术报告的最新修订版可在 W3C 标准和草案 索引中找到。

这是一份实验性规范,并且正在定期修订。它 不适合用于生产部署。

本文档由可验证凭证工作 组作为 工作草案发布,并使用 推荐标准轨道。

作为工作草案发布并不 意味着获得 W3C 及其成员的认可。

这是一份草案文档,可能随时被其他文档 更新、替换或废弃。除作为正在进行中的工作外, 不宜引用本文档。

本文档由一个根据 W3C 专利 政策运作的小组制作。 W3C 维护一个 任何专利披露的公开列表, 这些披露与该小组的交付物有关; 该页面还包含 披露专利的说明。任何实际 知悉某项专利并认为该专利包含 必要权利要求的个人, 必须根据 W3C 专利政策第 6 节披露相关信息。

本文档受 2025年8月18日 W3C 流程文档管辖。

1. 简介

当颁发者希望以特定方式通过 视觉、听觉或触觉机制向观察者表达可验证凭证时, 可以使用渲染方法。例如,某个 员工徽章凭证的颁发者可能希望 加入其公司徽标的丰富图像,并将员工信息按特定方式放置在 徽章的特定区域。他们可能还希望为 有与视力相关的无障碍需求的个人提供徽章重要内容的 音频朗读。

1.1 术语

本文档中使用的一些术语定义于 可验证凭证数据模型 v2.1规范的 术语一节中。

1.2 一致性

除标记为非规范性的章节外,本规范中的所有编写指南、图示、示例和注释 均为非规范性的。本规范中的其他所有内容均为规范性的。

本文档中的关键词 可以、必须、不得 、可选、建议、必需 和 应该 仅当它们像此处所示以全大写形式出现时, 才应按照 BCP 14 [RFC2119] [RFC8174] 中的说明进行 解释。

符合规范的渲染方法是数据模型的任何具体表达, 其符合本规范中的规范性陈述。 具体而言,本文档第 2. 数据模型和3. 算法 节中的所有相关规范性陈述都必须得到执行。

符合规范的处理器是任何以 软件和/或硬件实现、用于生成或使用 符合规范的渲染方法的算法。符合规范的处理器在 使用不符合规范的文档时必须产生错误。

本文档还包含含有 JSON 和 JSON-LD 内容的示例。其中一些 示例包含对 JSON 而言无效的字符,例如内联 注释(//),以及使用省略号(...)表示 对示例几乎没有附加价值的信息。如果实现者希望将这些信息作为有效的 JSON 或 JSON-LD 使用,应注意移除这些内容。

2. 数据模型

以下各节概述本规范用于 渲染方法的数据模型

2.1 renderMethod 属性

renderMethod 属性是 可验证凭证数据模型 v2.1规范中的一个保留扩展点。颁发者可以在 可验证凭证中使用此属性, 以表达一个或多个首选渲染方法。

renderMethod
renderMethod 属性的值必须指定一个或 多个可供软件使用、通过 视觉、听觉或触觉机制表达可验证 凭证的渲染方法。每个 renderMethod 值都必须指定其 type,例如 SuiteRenderMethod。每个渲染 提示的具体内容由 renderSuite 属性所指定的 渲染套件决定。

2.2 SuiteRenderMethod

当颁发者 希望为 可验证凭证指定渲染指令时, 其可以添加一个使用 下述数据模型的 renderMethod 属性。具体渲染行为由 renderSuite 属性中命名的渲染套件决定。 每个渲染套件定义其使用下述哪些属性;请参阅 各渲染套件章节。

属性 描述
id 一个可选的字符串,其遵循URL 标准,并且在获取时, 解引用为一个渲染模板。
type 一个必需的字符串,其值必须为 SuiteRenderMethod。
renderSuite 一个必需的字符串,用于标识渲染 套件,即用于生成具体渲染结果的 一组算法。该值是普通 JSON 字符串,并使用精确、区分大小写的匹配方式进行比较。本 规范定义了 static、summary 和 html 这些值。实现 必须忽略其 renderSuite 值无法 识别或不支持的任何 renderMethod 条目。
name 一个可选的、人类可读的字符串,可显示以提供 关于将执行何种渲染的 提示。此属性可用于 允许个人在多种 呈现模式之间进行选择的图形界面。
description 一个可选的、人类可读的字符串,其提供比 name 更详细的描述, 说明特定渲染何时可能有用。
renderProperty 一个可选的列表,其中包含多个字符串值,每个值都符合 JavaScript 对象表示法(JSON) 指针语法,用于指定在使用此特定渲染方法时可验证 凭证中的哪些属性会被公开。如果未提供 renderProperty,则在使用渲染方法时,整个可验证 凭证都 被视为将被共享。
template 一个可选的URL 或映射,用于 提供或引用将用于执行渲染的 模板。如果该值是URL, 则其可以是包含模板代码的 data: URL [RFC2397]。如果该值 是映射,则其必须符合以下规则:
属性 描述
id 一个必需的字符串,其遵循 URL 标准,并且 在获取时, 解引用为 SVG 或 PDF 文件等模板。
mediaType 一个建议的字符串,用于标识 id 值的媒体类型, 其定义见媒体类型 规范和注册程序。
digestMultibase 模板文件的一个可选的 multibase 编码 Multihash。 multibase 值必须为 u(base64url-nopad),且 multihash 值必须为输出长度为 256 位的 SHA-2(0x12)。
digestMultibase 如果指定了 id,则为所引用渲染方法的一个可选的 multibase 编码 Multihash。 multibase 值必须为 u (base64url-nopad),且 multihash 值必须为输出长度为 256 位的 SHA-2(0x12)。
问题 1: renderSuite 值的注册表

渲染套件值应注册在何处(本规范中的注册表章节、 VC 规范目录,或两者皆是),以及扩展 套件值是普通字符串还是 URL,目前仍在讨论中。

2.2.1 summary 渲染套件

summary 渲染套件使用 JSON 模板将 可验证 凭证转换为标准化的数据显示格式。此格式 使钱包能够以响应式布局显示凭证,并突出显示关键 数据以及可配置的附加字段。实现 此方法的钱包可以在自己的 UI 设计中渲染标准化 JSON 输出,因此即使钱包本身 不原生支持特定凭证类型,也能显示凭证。

模板和渲染输出都是共享 同一定义(即下述摘要对象)的 JSON 对象。模板中的字符串值 可以是 JSON 指针字符串(如JavaScript 对象表示法(JSON) 指针中所规定),这些字符串 引用可验证 凭证中的值。在处理 模板时,会针对凭证数据求值 JSON 指针字符串, 并将其替换为解析得到的值。模板和最终 输出都必须符合摘要对象定义。不支持跨 多个字段的复合数据;每个字段引用单个 JSON 指针。

2.2.1.1 通用 属性的使用

summary 渲染套件按以下方式使用通用渲染方法属性:

属性 在此套件中的使用方式
template 提供摘要模板,该模板可作为 data: URL 嵌入,或 作为映射 被引用。该值必须是或解引用为一个 JSON 文档,且该文档符合 2.2.1.2 摘要对象中的摘要对象定义。
renderProperty 此套件不使用该属性。摘要模板中的 JSON 指针字符串 决定可验证 凭证中的哪些属性会被公开。
outputPreference 可以提供。accessMode 和 style 偏好适用于 渲染后摘要的显示。
2.2.1.2 摘要对象

摘要对象是一个 JSON 对象 [RFC8259], 其成员定义如下。 同一定义既适用于模板,也适用于渲染输出。在 模板中,任何定义为字符串的成员,其值可以改为 一个 JSON 指针字符串(以 / 开头,如JavaScript 对象表示法(JSON) 指针中所规定),用于 引用可验证 凭证中的值,但字段对象的 label 和 value 成员另有说明。在渲染输出中, 每个 JSON 指针都已被其解析值替换。

name
一个必需的字符串,包含凭证 摘要的显示名称。
description
一个必需的字符串,包含凭证 摘要的描述文本。
icon
一个可选的字符串,包含用于在摘要中显示的图标或图像的URL 或 data: URL [RFC2397]。
theme
一个可选的颜色主题对象,包含以下成员:
primaryColor
一个可选的字符串,包含用于 背景和 突出显示的主颜色。
accentColor
一个可选的字符串,包含用于 突出显示和强调的强调色。
fields
一个必需的自定义数据字段数组,按显示顺序排列。每个 字段都是一个 包含以下成员的对象:
label
一个必需的字符串,包含字段标签。在 模板中,标签必须 是字面字符串;此处不允许使用 JSON 指针。
value
一个必需的字符串,包含字段值。在 模板中,该值必须 是 JSON 指针字符串(例如 "/issuer")。
language
一个可选的语言标签(如用于标识 语言的标签中所规定),用于指示 字段标签和/或值的语言。
direction
一个可选的方向标签(如Web 上的字符串:语言和 方向元数据中所规定),用于指示 字段标签和/或值的文本方向。
validFrom
一个可选的 ISO 8601 日期字符串,用于指示凭证何时 开始 有效。
validUntil
一个可选的 ISO 8601 日期字符串,用于指示凭证何时 不再 有效。

在处理前,模板应该根据上述摘要对象定义 进行 验证。摘要模板的非规范性 JSON Schema 见C. 摘要模板 JSON Schema。

2.2.1.3 摘要示例

以下示例展示一个包含 JSON 指针 字符串的有效摘要模板:

示例 1:摘要模板示例
{
  "name": "/credentialSubject/degree/name",
  "description": "大学学位凭证",
  "icon": "/credentialSubject/icon",
  "theme": {
    "primaryColor": "#1a5490",
    "accentColor": "/credentialSubject/theme/accentColor"
  },
  "fields": [
    {
      "label": "院校",
      "value": "/issuer"
    },
    {
      "label": "学位类型",
      "value": "/credentialSubject/degree/type"
    },
    {
      "label": "颁发日期",
      "value": "/validFrom"
    }
  ],
  "validFrom": "/validFrom",
  "validUntil": "/validUntil"
}

以下示例展示一个有效的摘要输出:

示例 2:摘要输出示例
{
  "name": "理学与文学学士",
  "description": "大学学位凭证",
  "icon": "https://example.edu/icons/degree.svg",
  "theme": {
    "primaryColor": "#1a5490",
    "accentColor": "#4a90e2"
  },
  "fields": [
    {
      "label": "院校",
      "value": "示例大学"
    },
    {
      "label": "学位类型",
      "value": "BachelorDegree"
    },
    {
      "label": "毕业日期",
      "value": "2010-05-15"
    }
  ],
  "validFrom": "2010-01-01T19:23:24Z",
  "validUntil": null
}

在以下示例中,JSON 模板作为 data: URL [RFC2397] 直接嵌入 可验证 凭证中。

示例 3:summary 渲染 套件的基本用法
{
  ...
  "renderMethod": {
    "type": "SuiteRenderMethod",
    "renderSuite": "summary",
    // JSON 模板嵌入在 VC 中
    "template": "data:application/json;base64,eyJuYW1lIjogIi9jcmVkZW50aWFsU3ViamVjdC9kZWdyZWUvbmFtZSIsICJkZXNjcmlwdGlvbiI6ICJVbml2ZXJzaXR5IERlZ3JlZSBDcmVkZW50aWFsIiwgImZpZWxkcyI6IFt7ImxhYmVsIjogIkluc3RpdHV0aW9uIiwgInZhbHVlIjogIi9pc3N1ZXIifV19"
  }
}

下一个示例链接到 Web 上的 JSON 模板,并通过 digestMultibase 属性防止其被修改。

示例 4:用于摘要渲染模板的远程托管 JSON 模板
{
...
"renderMethod": {
  "type": "SuiteRenderMethod",
  "renderSuite": "summary",
  "template": {
    // 此 JSON 模板从 Web 获取
    "id": "https://degree.example/credential-templates/bachelors.json",
    "mediaType": "application/json",
    "digestMultibase": "zQmerWC85Wg6wFl9znFCwYxApG270iEu5h6JqWAPdhyxz2dR"
  }
}

下一个示例链接到 Web 上的渲染模板,并使用 digestMultibase 属性保护该模板:

示例 5:远程托管的 summary 渲染 方法
{
...
"renderMethod": {
  // 此渲染方法从 Web 获取
  "id": "https://degrees.example/bachelors-card.jsonld",
  "mediaType": "application/ld+json",
  "type": "SuiteRenderMethod",
  "renderSuite": "summary",
  "digestMultibase": "zQmG270iEu5h6JqWAPdhyxz2dRerWC85Wg6wFl9znFCwYxAp"
}

2.2.2 html 渲染 套件

html 渲染套件允许模板作者提供 HTML 模板, 用于渲染可验证 凭证。HTML 可以通过远程引用,或者 以 data: URL 的形式作为 template 或 template.id 的值(当 template 的值为对象时)提供。HTML 片段中的 JavaScript 负责渲染经过筛选的可验证 凭证数据,该数据 通过 HTML 数据块 (即 <script type="application/vc"></script>)提供,并与 HTML 模板一起托管在 沙盒化 iframe 中。

示例 6:使用 HTML 渲染套件的 VC 示例
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://www.w3.org/ns/credentials/examples/v2"
  ],
  "type": [
    "VerifiableCredential",
    "NameCredential"
  ],
  "issuer": {
    "id": "did:example:1234",
    "name": "颁发者"
  },
  "credentialSubject": {
    "name": "示例名称",
    "notRendered": "不应显示"
  },
  "renderMethod": {
    "type": "SuiteRenderMethod",
    "renderSuite": "html",
    "renderProperty": [
      "/issuer/name",
      "/credentialSubject/name"
    ],
    "template": {
      "id": "https://test.example/credential-templates/NameCredential.html",
      "mediaType": "text/html",
      "digestMultibase": "zQmerWC85Wg6wFl9znFCwYxApG270iEu5h6JqWAPdhyxz2dR"
    },
    "outputPreference": {
      "accessMode": [
        "visual"
      ],
      "mediaType": "application/html",
      "style": {
        "width": "800px",
        "height": "800px"
      }
    }
  }
}
2.2.2.1 通用 属性的使用

html 渲染套件按以下方式使用通用渲染方法属性:

属性 在此套件中的使用方式
template 提供 HTML 片段,该片段可作为 data: URL 嵌入,或 作为 id 解引用到该片段的映射进行引用。
renderProperty 可以提供,用于限制传递给 模板的可验证 凭证数据。如果不存在,则提供整个可验证 凭证。
outputPreference 可以提供。style 的 width 和 height 偏好适用于 托管模板的 iframe。

实现必须提供一个允许 JavaScript 使用经过筛选的可验证 凭证数据安全地 渲染 HTML 模板的环境。 此外,宿主页面应该通过使用 Oblivious HTTP [RFC9458] 或其他通过使用保护性中继将请求客户端与被请求源解除关联的方法, 保护任何请求(例如解引用 template.id)的 隐私。

以下术语用于描述此环境:

宿主 页面
提供用于渲染 HTML 模板的安全环境。
模板 代码
在渲染方法中提供或由其远程引用的 HTML 片段。
包装 代码
包装 HTML 模板以提供附加安全 限制并与宿主页面通信的代码。

至少,该环境必须阻止导航、加载 外部 内容以及访问宿主页面,以防止跟踪 和其他 隐私损害。

该环境还必须向模板代码公开用户环境中可用的所有 国际化和无障碍设置。这使模板能够遵循个人已经向 其用户代理或操作系统表达的语言、文本大小、 对比度和动画偏好。此类设置的示例包括 CSS 中反映的设置,例如 rem 单位以及 prefers-contrast、prefers-reduced-motion 和 forced-colors 等媒体查询,还包括 JavaScript 可用的设置,例如由 Intl 和 Navigator.language 提供的区域设置信息。

例如,基于浏览器的实现可以通过以下组合提供此类环境: 宿主页面上的内容安全策略 [CSP3] 限制、 对托管 HTML 模板的 iframe 进行沙盒化,以及使用包装 代码包装 HTML 模板以添加额外的 CSP 限制,并 提供与宿主页面之间的就绪和错误事件通信。

沙盒化的 iframe 默认满足上述国际化和无障碍 要求。本节所述的沙盒和 CSP 限制 不会干扰 CSS 媒体查询,也不会干扰 Intl 和 Navigator.language 等 JavaScript API。html 渲染套件也可以使用其他渲染环境, 例如移动平台上的 WebView。

图 1 宿主页面与 iframe + 包装代码之间的通信
2.2.2.2 宿主页面

宿主页面(通常是钱包或可验证 凭证渲染器)必须 阻止 HTML 模板导航顶级浏览上下文、 访问外部内容、访问宿主页面以及 加载任何远程 内容。

如果使用宿主页面,则适用以下规则:

  • 内容安全策略(CSP)限制必须包括 frame-src 'none'。 这会强制 iframe 使用 srcdoc 而不是 src,从而 阻止 浏览器加载 HTML 模板。反过来,这会迫使 宿主页面代码预加载远程引用的模板 代码,并在将 模板注入包装代码之前,根据相关 digestMultibase 值检查 响应。
  • 托管 HTML 模板的 iframe 上必须设置 sandbox="allow-scripts",以阻止导航和顶级访问。
示例 7:最小宿主页面
<html>
  <head>
    <meta http-equiv="content-security-policy" content="frame-src 'none'">
  </head>
  <body>
    <iframe id="renderer" sandbox="allow-scripts allow-modals" srcdoc=""></iframe>
  </body>
</html>
2.2.2.2.1 模板代码

renderMethod 中 template 属性引用的 HTML 模板代码必须是一个包含 渲染可验证 凭证所需 HTML、CSS 和 JavaScript 的 HTML 片段。该 模板代码不得 包含任何 <html>、<head> 或 <body> 标签, 因为这些标签将由包装 代码提供。

示例 8:HTML 模板片段示例
<div>
  <script>
    document.addEventListener('DOMContentLoaded', (event) => {
      console.log('running template render script');

      // 作为示例渲染器,以 JSON 形式显示凭证;这里也可以
      // 执行任何其他操作,包括 mustache/其他风格的
      // 模板处理,以生成用于显示的 HTML

      // FIXME: 确定数据块/script 标签的最佳名称/位置
      const credential = JSON.parse(document.querySelector(
        'head > script[name="credential"]').innerHTML);

      document.querySelector('#credentialSubject-name').innerText =
        credential.credentialSubject.name;
      document.querySelector('#issuer-name').innerText =
        credential.issuer.name;

      // TBD: 向宿主发出渲染已完成的信号
      window.renderMethodReady();
    });
  </script>
  <style>
    h1 {
      color: blue;
    }
  </style>

  <h1 id="credentialSubject-name"></h1>
  <p>颁发者:<span id="issuer-name"></span></p>
</div>
2.2.2.2.2 包装代码

模板 HTML 片段必须包装在包装代码 中,该代码提供包含部分可验证 凭证的数据块, 并添加额外的 CSP 策略,以阻止导航和外部 内容加载。具体而言,包装 代码必须添加以下 CSP 限制 default-src data: 'unsafe-inline',以阻止 模板 代码发出任何网络请求。

示例 9:用于在 iframe[srcdoc] 中包装模板和 凭证的包装代码
<html>
  <head>
    <meta http-equiv="content-security-policy" content="default-src data: 'unsafe-inline'">
    <script name="credential" type="application/vc">${JSON.stringify(credential)}</script>
  </head>
  <body>${template}</body>
</html>

为完成设置,宿主页面必须将包装 代码(在填入 可验证 凭证和模板代码后)注入 iframe 的 srcdoc 属性,这将运行包装 代码和模板代码中包含的任何 JavaScript。

示例 10:包含模板 和凭证的组合包装代码
<html>
  <head>
    <meta http-equiv="content-security-policy" content="default-src 'none' data: 'unsafe-inline'">

<!-- 注入包装代码中的凭证数据块。 -->
<script name="credential" type="application/vc">{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://www.w3.org/ns/credentials/examples/v2"
  ],
  "type": [
    "VerifiableCredential",
    "NameCredential"
  ],
  "issuer": {
    "id": "did:example:1234",
    "name": "颁发者"
  },
  "credentialSubject": {
    "name": "示例名称"
  }
}</script>
<!-- 凭证数据块结束 -->

</head>
<body>

<!-- 注入包装代码中的模板 HTML。 -->
<div>
  <script>
    console.log('running template render script');

    // 作为示例渲染器,以 JSON 形式显示凭证;这里也可以
    // 执行任何其他操作,包括 mustache/其他风格的
    // 模板处理,以生成用于显示的 HTML

    // FIXME: 确定数据块/script 标签的最佳名称/位置
    const credential = JSON.parse(document.querySelector(
      'head > script[name="credential"]').innerHTML);

    document.querySelector('#credentialSubject-name').innerText =
      credential.credentialSubject.name;
    document.querySelector('#issuer-name').innerText =
      credential.issuer.name;

    // TBD: 向宿主发出渲染已完成的信号
    window.renderMethodReady()
  </script>
  <style>
    h1 {
      color: blue;
    }
  </style>

  <h1 id="credentialSubject-name"></h1>
  <p>颁发者:<span id="issuer-name"></span></p>
</div>
<!-- 模板 HTML 结束 -->

  </body>
</html>
2.2.2.2.3 就绪和 错误事件

在包装代码中创建的 iframe 必须提供通信通道, 使模板能够在渲染 完成或渲染期间 发生错误时通知宿主页面。这可以通过 postMessage API 和由包装代码设置的 MessageChannel 来实现。

以下所示的 JavaScript 将添加到上述宿主页面中,为 iframe 添加一个 onload 事件,以设置 MessageChannel。该 宿主页面 还会创建一个 Promise,当从 包装代码收到 ready 消息时兑现,或在收到 error 消息时拒绝。包装代码 还提供一个供模板使用的 window.renderMethodReady 方法,用于 通知宿主页面渲染已完成或返回 错误消息。

示例 11:为宿主页面添加内容以设置 MessageChannel
// 一个在渲染就绪时兑现(或在渲染失败时
// 拒绝)的 promise;可用于改为显示渲染内容或错误
let resolveRender;
let rejectRender;
const readyPromise = new Promise((resolve, reject) => {
  resolveRender = resolve;
  rejectRender = reject;
});

// 设置供 iframe 中模板代码使用的通信通道
renderer.onload = () => {
  // 创建一个 MessageChannel;将一个端口传输给 iframe
  const channel = new MessageChannel();
  // 启动消息队列,使 iframe 加载期间消息不会丢失
  channel.port1.start();
  // 处理 `ready` 消息
  channel.port1.onmessage = function ready(event) {
    if(event.data === 'ready') {
      // iframe 已就绪,因此取消隐藏
      resolveRender();
    } else {
      rejectRender(new Error(event.data?.error?.message));
    }
    channel.port1.onmessage = undefined;
  };
  // 发送 "start" 消息;将 `port2` 发送给 iframe 以进行返回通信
  renderer.contentWindow.postMessage('start', '*', [channel.port2]);
};

// 设置对就绪或错误事件的响应
// 注:本节特定于钱包/渲染器的 UX 需求
readyPromise.then(() => {
  console.log('rendering ready');
  const renderer = document.getElementById('renderer');
  renderer.hidden = false;
}).catch(err => {
  const errorMessage = document.getElementById('error-message');
  errorMessage.style.display = 'block';
  errorMessage.innerText = '渲染失败:' + err.message;
  console.error('rendering failed', err);
});
示例 12:连接 MessageChannel 并创建 `renderMethodReady` 的包装代码附加内容
// 添加一个将兑现为来自
// 父窗口的通信端口的 promise
const portPromise = new Promise(resolve => {
  window.addEventListener('message', function start(event) {
    if(event.data === 'start' && event.ports?.[0]) {
      window.removeEventListener('message', start);
      resolve(event.ports[0]);
    }
  });
});

// 将一个函数附加到 window,供模板在
// “就绪”(或发生错误)时调用,该函数将发送消息
// 给父窗口,使父窗口可以决定是否显示 iframe
window.renderMethodReady = function(err) {
  portPromise.then(port => port.postMessage(
    !err ? 'ready' : {error: {message: err.message}}));
};

在此设置下,模板 JavaScript 可以调用 window.renderMethodReady() 来通知宿主页面渲染已完成,或调用 window.renderMethodReady(new Error("错误消息")) 来通知宿主页面 发生了错误。

2.2.2.3 输出偏好

渲染环境偏好可以在渲染 方法中提供。该 对象的目的是在渲染所提供模板时,提供关于使用方式、显示方式和预期 访问模式的建议。实现应该 在提供这些偏好时遵循它们。

属性 描述
outputPreference 一个可选的映射,用于表达 所提供模板的首选渲染环境。

outputPreference 对象可以包含以下任意 属性:

属性 描述
accessMode 一个可选的列表,包含一个或多个字符串 值 auditory、tactile、 textual 或 visual,定义见 https://w3c.github.io/cg-reports/a11y-discov-vocab/CG-FINAL-vocabulary-20260128/#accessMode-vocabulary
mediaType 一个可选的字符串,用于指定 IANA 媒体 类型中列出的、首选用于渲染的有效媒体 类型。该值可以 在建议渲染前执行附加处理时使用。示例包括将 SVG 模板转换为静态图像,或将 HTML 文档转换为 PDF。
style 一个可选的映射,用于定义 渲染环境可能使用的样式 属性。

style 对象可以包含以下任意 属性:

属性 描述
width 一个可选的字符串,包含一个兼容 CSS 的 宽度偏好,用于设置在 iframe 上。
height 一个可选的字符串,包含一个兼容 CSS 的 高度偏好,用于设置在 iframe 上。

2.2.3 static 渲染套件

static 渲染套件用于交付表示 可验证 凭证的各种静态或预渲染二进制格式的二进制有效载荷, 例如图像、PDF 或嵌入式 NFC 有效载荷。

在下面的示例中,完全嵌入的 NFC 有效载荷用作渲染 模板,该模板仅披露与该 凭证关联的条码标识符。

示例 13:“static”渲染套件的用法
{
...
"renderMethod": {
  "type": "SuiteRenderMethod",
  "renderSuite": "static",
  "deliveryMode": "nfc",
  "name": "轻触以发送",
  // NFC 有效载荷已嵌入
  "template": "data:application/octet-stream;base64,2QZkpQGDG...G8XJWnROcY4Biw",
  // 仅通过 NFC 传输条码
  "renderProperty": ["/credentialSubject/barcode"]
}
...
}
2.2.3.1 通用 属性的使用

static 渲染套件按如下方式使用通用渲染方法属性:

属性 在此套件中的使用
template 提供静态二进制有效载荷,通常作为 data: URL 嵌入。
deliveryMode 指定渲染模板的预期交付方法,例如 nfc 用于通过无线 NFC 信道传输。
renderProperty 可以提供该属性,以限制渲染模板中表示哪些可验证 凭证数据 。
outputPreference 此套件通常不使用该属性。

3. 算法

以下各节概述本规范用于 渲染方法的算法。

3.1 摘要模板处理

处理摘要模板时,以下步骤必须 执行:

  1. 根据 2.2.1.2 摘要对象中的摘要对象定义验证模板。如果验证失败,处理必须停止,并且 必须返回错误。
  2. 对模板对象中的每个字符串值:
    1. 如果字符串值以 / 开头(表示它是 JSON 指针), 则使用 JSON 指针算法 JavaScript 对象表示法(JSON) 指针对 可验证 凭证进行求值,并将其作为目标文档。
    2. 如果 JSON 指针求值成功,则将 JSON 指针字符串替换为 解析得到的值。如果解析得到的值不是字符串,则将其转换为 字符串表示形式。
    3. 如果 JSON 指针求值失败或返回 null,则行为由 具体实现决定。实现可以使用空字符串、 将 值保留为 null,或发出错误信号。
    4. 如果字符串值不以 / 开头,则将其视为字面字符串 并保持不变。
  3. 根据摘要对象定义验证生成的 JSON 对象 ,该定义见 2.2.1.2 摘要对象。如果验证失败,处理必须停止,并且 必须返回错误。

请注意,不支持跨多个字段的复合数据。模板中的每个字段 都引用一个解析为凭证中单个 值的 JSON 指针。

3.2 HTML 模板处理

以下各节概述 html 渲染 套件用于安全渲染 HTML 模板的算法。只要安全和隐私结果以及输出相同,就可以使用替代算法 。

3.2.1 宿主页面

宿主页面必须创建一个 iframe 元素来托管 HTML 模板。 宿主页面必须将 iframe 上的 sandbox 属性设置为 allow-scripts,以阻止导航和顶级访问。

  1. 令 vc 为要渲染的可验证 凭证。
  2. 令 renderMethod 为 vc 中选定的 renderMethod 属性,其中 renderMethod.type 为 SuiteRenderMethod,并且 renderMethod.renderSuite 为 html。
  3. 如果 renderMethod.template 是字符串,则令 template 为 renderMethod.template 的 值。
  4. 如果 renderMethod.template 是映射,则令 template 为 获取 renderMethod.template.id 中 URL 的结果。

宿主页面必须筛选可验证 凭证 vc,使其仅包含 renderMethod.renderProperty 中指定的属性(如果该属性存在)。如果 renderMethod.renderProperty 不存在,则使用整个可验证 凭证 。

此筛选必须通过应用 Data Integrity ECDSA Cryptosuites v1.0 规范中定义的 第 3.4.13 节 selectJsonLd 算法 [VC-DI-ECDSA],对 renderMethod.renderProperty 中存在的 JSON 指针 [RFC6901] 值进行处理来完成。

宿主页面必须通过嵌入筛选后的 可验证 凭证和 HTML 模板来创建包装代码,并将其嵌入包装代码 模板 中。

  1. 令 wrapperCode 为一个 HTML Document,其 <head> 中包含 <meta http-equiv="Content-Security-Policy" content="default-src data: 'unsafe-inline'">。
  2. 令 datablock 为一个 type 为 application/vc 的 HTML 数据块。
  3. 将 datablock 的内容设置为经过筛选的可验证 凭证 的字符串化 JSON 格式。
  4. 将 datablock 插入 wrapperCode 的 <head> 中。
  5. 将 template 的值插入 wrapperCode 的 <body> 中。

宿主页面必须将 iframe 的 srcdoc 属性 设置为生成的包装代码。

  1. 将 iframe 的 srcdoc 属性设置为 wrapperCode 的字符串化 HTML。

宿主页面必须与包装代码建立通信 通道,以 接收如上所述的 ready 和 error 消息。

  1. 令 renderPromise 为一个新的 Promise,其:
    1. 在 resolve 时,可用于向用户显示 iframe。
    2. 在 reject 时,向用户显示错误消息。
  2. 在 iframe 的 onload 事件中:
    1. 令 channel 为一个新的 MessageChannel。
    2. 在 channel 上创建并启动一个新的 port1 监听器,用于监听 来自当前已注入 iframe 的 template 中代码的 ready 消息,该代码通过 wrapperCode 注入。
    3. 在 port1 监听器中,如果收到 ready 消息,则兑现 renderPromise。 如果收到 error 消息,则以该错误 消息拒绝 renderPromise。
    4. 使用 postMessage 将 channel 的 port2 发送到 iframe 内容窗口。

宿主页面应该使用 renderPromise 来确定渲染何时 完成,或渲染期间是否发生错误。

3.2.2 包装代码

包装代码必须设置为接收 通过 MessageChannel 来自宿主页面的 通信,并提供 window.renderMethodReady 方法供 模板代码使用。

  1. 在 window.onload 事件中……
    1. 令 port 为通过 message 事件从宿主页面接收到的 MessagePort。
    2. 创建 window.renderMethodReady 函数,其……
      1. 如果调用时不带参数,则向宿主页面发送 ready 消息,该消息通过 port 发送。
      2. 如果调用时带有 Error 参数,则发送 error 消息给宿主页面 ,并通过 port 携带错误消息。

A. 威胁模型

本节为非规范性内容。

本节总结了本规范的威胁模型,涵盖与渲染方法的发布、检索和 处理相关的安全和隐私注意事项。完整分析,包括应对措施和 数据流图,见 可验证凭证渲染方法威胁 模型。

强烈建议读者先熟悉 可验证凭证数据模型 v2.1 规范中 威胁模型一节提供的一般威胁模型,再阅读本节。实现者 应将该规范中提供的一般分析应用于 本规范提供的每项具体功能。

A.1 目标威胁

  1. 不受控制的凭证呈现 安全 - 如果没有由颁发者声明的渲染方法,如何显示 可验证 凭证完全由持有者或验证者 软件决定, 这些软件可以省略声明、重新排序或重新标记字段、丢弃有效性信息,或 应用误导性的品牌标识,从而使观察者对 颁发者所证明的内容形成错误理解,即使 凭证本身是真实的。

A.2 实现威胁

  1. 不安全地渲染不受信任的数据 安全 - html 渲染套件会执行模板提供的代码,并使用属于不受信任输入的凭证 值,因此,即使恶意内容包含在格式正确且已验证的凭证中,也可能尝试访问周围的 宿主页面、导航到其他位置,或在 渲染期间联系外部位置。

A.3 部署威胁

  1. 通过模板和资源获取进行跟踪 隐私 - 通过位置检索模板或其引用的资源会向 颁发者或 主机暴露正在渲染某个凭证,而每凭证 位置或编码到出站请求中的凭证数据,会使每次渲染 都成为跟踪或数据外泄信号。

A.4 外部威胁

  1. 有害的渲染输出 安全 - 由于渲染模板控制视觉、听觉和触觉输出, 恶意模板可能被设计为伤害查看它的人,例如使用 可能诱发癫痫发作的闪烁图案或突然出现的干扰性声音, 即使底层凭证是真实的。

A.5 依赖项威胁

  1. 继承的渲染环境攻击面 安全 - html 渲染套件依赖所选 渲染环境所提供的限制,因此,任何允许逃逸沙盒、绕过策略或 破坏模板与宿主之间隔离的缺陷,都会成为 渲染过程中的缺陷,即使渲染方法完全按照规范使用。

安全注意事项

W3C 正在迁移到一种整体性的威胁建模方法, 并且正在 新规范中逐步弃用“安全注意事项”章节。 有关安全注意事项的文档,请参阅附录 A. 威胁模型。

隐私注意事项

W3C 正在迁移到一种整体性的威胁建模方法, 并且正在 新规范中逐步弃用“隐私注意事项”章节。有关隐私 注意事项的文档,请参阅附录 A. 威胁模型。

B. 与其他技术的关系

本节为非规范性内容。

已考虑若干现有方法和技术,用于传达由 颁发者首选且人类可感知的可验证凭证呈现方式。 本节总结这些替代方案,以及为何选择 本规范所述的渲染方法方案。

客户端决定的渲染

不定义任何机制并将呈现交由持有者或验证者 软件处理,不需要额外数据,但这使颁发者无法传达 预期的呈现方式,因此凭证渲染不一致,并且声明或 品牌标识可能被错误呈现,如 不受控制的 凭证呈现中所述。诸如 ISO/IEC 18013-5 移动驾驶 许可证(mDL)和 JSON Web Token (RFC 7519)等凭证格式采用这种 方法,它们定义凭证携带的声明,但将其 呈现交由使用这些凭证的软件处理。Microsoft 的 Information Card (CardSpace,现已停止使用)采用了这种方法的一种受限变体,允许 颁发者仅提供 卡片名称和徽标,并由身份选择器在 统一的卡片界面中渲染。本规范增加了由颁发者声明的替代方案, 而不是禁止由客户端决定的渲染。

特定凭证类型的显示注册表

通过注册表按凭证类型标准化呈现,可以为已知类型提供一致的 渲染,但需要预先了解每种类型,无法 扩展到自定义凭证,也无法表达特定于颁发者的品牌标识。 诸如 Apple Wallet (PassKit)、 Google Wallet 和 Samsung Wallet 等平台钱包采用这种 方法,在固定的、由平台控制的布局中渲染一组预定义的固定通行证或对象类型, 其中颁发者可以填写字段值 和资源,但无法表达平台目录之外的布局或品牌标识。 本规范定义的渲染方法策略则随凭证一起传递,或 由凭证引用,因此即使是不熟悉的类型,也可以按照 其颁发者的预期方式进行渲染。

这种集中式、受控且以注册表为中心的解决方案,也与 原本规定为 去中心化标识符(DID)和 可验证凭证(VC)生态系统组成部分的 分布式、去中心化和无需许可的模式相冲突。

PDF、SVG 和 HTML 文档等呈现格式

分发完整渲染的 PDF、静态 SVG 或 HTML 文档 是自包含的且得到广泛支持,但此类快照无法适应 选择性披露,无法根据已验证数据重新渲染,并且 未与受保护的内容绑定。本规范复用这些格式,将其作为 在渲染时与声明值结合的模板,而不是作为完成的 文档。

数据完整性和证明机制

本规范不定义新的完整性机制,而是依赖 现有的保护机制,例如可验证凭证数据完整性 1.0以及 digestMultibase 属性,以 将所引用的模板绑定到凭证。读者可以通过阅读 篡改未受保护的外部资源威胁来了解这些一般 保护机制,该威胁见 可验证凭证威胁模型。

SD-JWT VC 类型元数据渲染

SD-JWT VC 定义了一个 rendering 属性,用于在支持 一组固定样式属性的 simple 方法与禁止 任何代码执行并将声明值替换到 SVG 文本占位符中的 svg_templates 方法之间进行选择。该小组研究了这种方法,并发现它对于实际 用例而言限制过多:由于占位符仅出现在文本节点中且无法运行代码, 因此无法表达条件字段、可变长度 列表、值格式化和响应式布局等数据驱动的呈现工具。这些 功能是医疗保健、零售和 银行/金融等领域的需求。相比之下,本规范并不绑定到单一的 凭证序列化格式,而是定义了跨越 无代码声明式 summary 套件、在受限的“沙盒化”环境中执行的数据驱动 html 套件,或 static 套件的渲染套件。

C. 摘要模板 JSON Schema

本节为非规范性内容。

以下 JSON Schema 实现 2.2.1.2 摘要对象中定义的摘要对象规则,这些规则适用于摘要模板。此 schema 是 非规范性的。

示例 14:摘要模板的 JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["name", "description", "fields"],
  "properties": {
    "name": {
      "type": "string",
      "description": "作为字面量字符串或 JSON 指针的显示名称(例如,\"/credentialSubject/degree/name\")"
    },
    "description": {
      "type": "string",
      "description": "作为字面量字符串或 JSON 指针的描述"
    },
    "icon": {
      "type": "string",
      "description": "作为字面量字符串或 JSON 指针的图标 URL 或 data: URL"
    },
    "theme": {
      "type": "object",
      "properties": {
        "primaryColor": {
          "type": "string",
          "description": "作为字面量字符串或 JSON 指针的主色"
        },
        "accentColor": {
          "type": "string",
          "description": "作为字面量字符串或 JSON 指针的强调色"
        }
      },
      "additionalProperties": false
    },
    "fields": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "required": ["label", "value"],
        "properties": {
          "label": {
            "type": "string",
            "description": "字段标签(字面量字符串;不允许使用 JSON 指针)"
          },
          "value": {
            "type": "string",
            "pattern": "^/",
            "description": "作为 JSON 指针字符串的字段值(以 \"/\" 开头)"
          },
          "language": {
            "type": "string",
            "description": "字段的可选 BCP 47 语言标签"
          },
          "direction": {
            "type": "string",
            "description": "字段的可选文本方向标签"
          }
        },
        "additionalProperties": false
      }
    },
    "validFrom": {
      "type": "string",
      "description": "作为字面量 ISO 8601 日期字符串或 JSON 指针的有效期开始日期"
    },
    "validUntil": {
      "type": "string",
      "description": "作为字面量 ISO 8601 日期字符串或 JSON 指针的有效期结束日期"
    }
  },
  "additionalProperties": false
}

D. 参考文献

D.1 规范性参考文献

[BCP47]
用于标识语言的标签。 IETF。URL:https://www.rfc-editor.org/info/bcp47
[CSP3]
内容安全策略第 3 级。Mike West; Antonio Sartori。W3C。2026 年 9 月 16 日。W3C 工作草案。URL:https://www.w3.org/TR/CSP3/
[infra]
Infra 标准。Anne van Kesteren;Domenic Denicola。WHATWG。现行标准。URL:https://infra.spec.whatwg.org/
[RFC2119]
用于在 RFC 中指示 要求级别的关键词。S. Bradner。IETF。1997 年 3 月。最佳当前实践。URL:https://www.rfc-editor.org/info/rfc2119/
[RFC2397]
“data” URL 方案。L. Masinter。IETF。1998 年 8 月。提议标准。URL:https://www.rfc-editor.org/info/rfc2397/
[RFC6838]
媒体类型规范和注册 程序。N. Freed;J. Klensin;T. Hansen。IETF。2013 年 1 月。最佳当前 实践。URL:https://www.rfc-editor.org/info/rfc6838/
[RFC6901]
JavaScript 对象表示法(JSON) 指针。P. Bryan, Ed.;K. Zyp;M. Nottingham, Ed.。IETF。2013 年 4 月。提议 标准。URL:https://www.rfc-editor.org/info/rfc6901/
[RFC8174]
RFC 2119 关键词中大写与小写的歧义。B. Leiba。IETF。2017 年 5 月。最佳当前实践。URL:https://www.rfc-editor.org/info/rfc8174/
[RFC8259]
JavaScript 对象表示法(JSON)数据 交换格式。T. Bray, Ed.。IETF。2017 年 12 月。互联网标准。URL:https://www.rfc-editor.org/info/rfc8259/
[STRING-META]
Web 上的字符串:语言和方向 元数据。Richard Ishida;Addison Phillips。W3C。2026 年 7 月 16 日。FPWD。URL:https://www.w3.org/TR/string-meta/
[URL]
URL 标准。Anne van Kesteren。WHATWG。 现行标准。URL:https://url.spec.whatwg.org/
[VC-DATA-MODEL-2.1]
可验证凭证数据模型 v2.1。Manu Sporny;Ted Thibodeau Jr;Ivan Herman。W3C。2026 年 9 月 30 日。W3C 工作草案。URL:https://www.w3.org/TR/vc-data-model-2.1/
[VC-DI-ECDSA]
数据完整性 ECDSA 密码套件 v1.0。Manu Sporny;Dave Longley;Greg Bernstein。W3C。2025 年 5 月 15 日。W3C 推荐标准。URL:https://www.w3.org/TR/vc-di-ecdsa/

D.2 资料性参考文献

[DID]
去中心化标识符(DID)v1.0。 Manu Sporny;Amy Guy;Markus Sabadello;Drummond Reed。W3C。2022 年 7 月 19 日。W3C 推荐标准。URL: https://www.w3.org/TR/did-core/
[RFC9458]
不经意 HTTP。M. Thomson;C. A. Wood。IETF。2024 年 1 月。建议标准。URL:https://www.rfc-editor.org/info/rfc9458/
[VC-DATA-INTEGRITY]
可验证凭据数据完整性 1.0。Ivan Herman;Manu Sporny;Ted Thibodeau Jr;Dave Longley;Greg Bernstein。 W3C。2025 年 5 月 15 日。W3C 推荐标准。URL:https://www.w3.org/TR/vc-data-integrity/
[VC-DATA-MODEL]
可验证凭据数据模型 v2.0。Ivan Herman;Michael Jones;Manu Sporny;Ted Thibodeau Jr;Gabe Cohen。W3C。 2025 年 5 月 15 日。W3C 推荐标准。URL:https://www.w3.org/TR/vc-data-model-2.0/