plainheart commented on code in PR #148: URL: https://github.com/apache/echarts-handbook/pull/148#discussion_r2444123588
########## contents/zh/best-practices/security.md: ########## @@ -0,0 +1,100 @@ +# 安全性 + +## 概述 + +ECharts 旨在提供丰富而灵活的可视化能力。虽然其绝大多数 API 不需要额外的安全考虑,但有几个例外。例如,`tooltip.formatter` 允许输入 HTML 字符串,从而完全控制组件的内容与布局;`title.link` 直接使用输入的 URL 字符串而不进行自动的净化处理(sanitization)。这种灵活性虽然强大,但当输入来自“不受信任”的来源时,可能带来安全风险。本文档列出了这些 API,并提供了如何安全使用这些特性的建议。 + +任何潜在安全问题,可通过邮件报告至 [[email protected]](mailto:[email protected])。 + + +## 安全边界与检查清单 [[[#security_boundaries_and_checklist]]] + +ECharts 专注于可视化逻辑,一般假定输入内容是可信任的,因此不会自动对输入进行净化处理。其实 ECharts 自身也不知如何合适地做净化处理,因为不存在适用于所有使用场景的通用处理规则。然而,ECharts 应该明确哪些 API(尤其是 ECharts options)在哪些场景下须在输入前进行安全相关的处理或考量。由于 ECharts options 数量庞大,对所有输入在任何场景下都进行安全处理不现实也无必要。 + +ECharts 通过 Canvas 或 SVG 渲染,只有几个特殊组件例外,允许 HTML 渲染(例如,[toolip](${optionPath}tooltip) 和 [dataView](${optionPath}toolbox.feature.dataView))。ECharts API 的输入可被分为“JS 函数”或者“非 JS 函数”。“JS 函数输入”本意就须允许执行。而大多数“非 JS 函数输入”(例如仅用于渲染的纯文本)不会被执行,因此通常无需防范恶意代码注入。然而,某些 API 允许在页面中嵌入不安全内容(如 HTML 或 URL 文本)。这些 API 能带来丰富的定制能力,但当输入来自“不受信任”的来源时,容易遭受 XSS (跨站脚本攻击)或相关攻击。 + +**一般而言,如果输入的内容都是可被信任的,就不会出现这些注入漏洞。** +“不受信任”(untrusted)的内容指,内容来自于无法完全控制的来源,或者内容可能被用户或外部系统修改或注入。开发者应该总是假定直接在 HTML、CSS、JS 中使用这些内容会不安全。例如,用户生成的数据或来自客户端的输入都应被认为是“不受信任”的。但在许多情况下,处理用户生成的内容不可避免。例如,从数据库获取用户生成的数据,并组装成 HTML 输入 `tooltip.formatter` 来渲染,就须要进行额外处理,首先是保正渲染正确(通常通过 HTML 转义(HTML escaping)),然后是防止 XSS 攻击(如果无法被转义的部分也是“不受信任”的,需要净化处理(sanitization))。 + +在部署图表之前,请根据以下**检查清单**确认使用是否安全: + +| APIs | 潜在风险与建议 | +| ------ | ------------------ | +| **option [tooltip.formatter](${optionPath}tooltip.formatter)**<br>· `formatter` 允许 HTML 文本或 DOM 元素传入,并后续直接渲染到 tooltip 内部,于是需要考虑 XSS 风险。<br>(例外):如果 `formatter` 被直接设置成一个字符串,则认为是一个内部实现的简单模版,后续能内部填入数据。[tooltip.renderMode: 'richText'](${optionPath}tooltip.renderMode) 是另一种内部实现的模版,用于定制样式。他们都不涉及 HTML,从而安全。<br><br>**option [toolbox.feature.dataView.optionToContent](${optionPath}toolbox.feature.dataView.optionToContent)**<br>**option [toolbox.feature.dataView.title](${optionPath}toolbox.feature.dataView.title)**<br>**option [toolbox.feature.dataView.lang](${optionPath}toolbox.feature.dataView.lang)**<br>· `tooltip.dataView` 面板完全以 HTML 渲染,这些 API 可自定义 HTML 文本中的部分内容,于是需要考虑 XSS 风险。 | 需要考虑 XSS 风险。一般情况 下,仅需 HTML 转义即可。但如果一些不能转义的部分来自“不受信任”的来源,则须更多处理(如净化处理(sanitization)或沙盒隔离)。<br><br>详细描述见 [“传入 HTML 时的安全考虑”](best-practices/security#passing_raw_html_safely)。 | +| **option [tooltip.extraCssText](${optionPath}tooltip.extraCssText)**<br>· `extraCssText` 接受一个原始 CSS style 字符串,并接下来直接拼接进 `tooltipEl.style.cssText`。<br>(例外):[tooltip.renderMode: 'richText'](${optionPath}tooltip.renderMode) 时此 `extraCssText` 无效。 | 若输入来自可信来源,则一般无安全问题,否则需要仔细评估风险。<br><br>详细描述见 [“传入内联 CSS 时的安全考虑”](best-practices/security#passing_inline_css_safely)。 | +| **option [title.link](${optionPath}title.link)**<br>**option [title.sublink](${optionPath}title.sublink)**<br>**option [series-treemap.data.link](${optionPath}series-treemap.data.link)**<br>**option [series-sunburst.data.link](${optionPath}series-sunburst.data.link)**<br>· 这些 option 直接接受原始 URL 字符串。 | 若若输入来自可信来源,则一般无安全问题,否则须要考虑 XSS 风险。<br><br>详细描述见 ["传入 URL 时的安全考虑"](best-practices/security#passing_raw_urls_safely)。 | +| **option [toolbox.feature.saveAsImage.name](${optionPath}toolbox.feature.saveAsImage.name)**<br>**option [toolbox.feature.saveAsImage.type](${optionPath}toolbox.feature.saveAsImage.type)**<br>**option [title[0].text](${optionPath}title.text)**<br>· `saveAsImage` 功能的下载文件名由 `{name}.{type}` 拼装而成,并未做额外校验或净化(sanitization)处理。如果 `name` 没有指定,则使用 `title[0].text` 替代,尽管这种用法并不推荐。 | 详细描述见 [“传入下载文件名时的安全考虑”](best-practices/security#passing_download_filename_safely)。 | +| 所有“JS 函数”输入(回调) | 通常无安全问题,除非存在特殊使用场景(例如需要执行不可信来源的函数)。<br><br>详细描述见 [“传入 JS 函数时的安全考虑”](best-practices/security#passing_js_function_safely)。 | + + +## 传入 HTML 时的安全考虑 [[[#passing_raw_html_safely]]] + +在 [“安全边界与检查清单”](best-practices/security#security_boundaries_and_checklist) 一节中已列出会接受原始 HTML 的 API。“不受信任”的 HTML 可能导致 XSS 等攻击,因此在传入 ECharts 前应进行处理。常见的处理方式包括 **HTML 转义(HTML Escaping)**、**净化(Sanitization)**、**沙盒**。大多数情况下,仅进行 HTML 转义即可,除非那些不能被转义的部分来自于“不受信任”的来源。 + +### HTML 转义(HTML Escaping) [[[#passing_raw_html_safely_html_escaping]]] +数据组装成 HTML 字符串前总需要进行 HTML 转义。这不仅是安全需要,也是正确显示的前提。 + +最简单和常见的 HTML 转义是这些字符串转换: +``` +'&' => '&' +'<' => '<' +'>' => '>' +'"' => '"' +"'" => ''' Review Comment: Should use escaped strings. ```suggestion '&' => '&' '<' => '<' '>' => '>' '"' => '"' "'" => '' ``` ########## contents/en/best-practices/security.md: ########## @@ -0,0 +1,97 @@ +# Security + +## Overview + +ECharts aims to provide rich and flexible visualization capabilities. Although the vast majority of its APIs do not require special security considerations, sereval APIs are exceptions. For example, the option `tooltip.formatter` accepts a raw HTML string, allowing full control over the component's content and layout; the option `title.link` uses the provided URL string directly without automatic sanitization. While this flexibility is powerful, security risks may arise if the input comes from untrusted sources. These APIs are listed below, along with suggestions on how to use these features safely. + +Any security issues can be reported to [[email protected]](mailto:[email protected]) . + + +## Security Boundaries and Checklist [[[#security_boundaries_and_checklist]]] + +ECharts focuses on visualization logic. It assumes that inputs are trusted, and does not automatically sanitize them. In fact, ECharts itself can not properly sanitize inputs, as there are no universal sanitization rules that applies to all use cases. However, ECharts should clearly identify which APIs (especially ECharts options) require security-related preprocessing or considerations in specific use cases. Given the large number of ECharts options, preprocess all inputs in every case would be impractical and unnecessary. + +ECharts renders using Canvas or SVG, except for several special components that allow HTML rendering (e.g., [toolip](${optionPath}tooltip), [dataView](${optionPath}toolbox.feature.dataView)). ECharts APIs accept Non-JS-function inputs and JS-function inputs. JS-function inputs are intended to be execute. Most non-JS-function inputs (e.g., plain text provided to be rendered) are treated as data only, and are inherently prevented from code evaluation and execution. Therefore, they generally do not require sanitization from malicious code. However, several APIs allow embeding potential unsafe content (for example, raw HTML or raw URLs) into the page. These APIs are powerful but vulnerable to Cross-Site Scripting (XSS) and related attacks if the inputs originate from untrusted sources. + +**Generally speaking, if no untrusted content is involved, these injection vulnerabilities will not arise.** Untrusted content refers to content that originates from a source that can not be fully controlled, or that can be modified or injected by users or external systems. Developers must assume it unsafe to use directly in HTML, CSS and JS. For example, content is untrusted if it is produced by users or received from a client. However, handling user-provided content is often unavoidable. For example, when rendering user data fetched from a database inside an HTML-based `tooltip` through a customized formatter, additional processing is required to ensure correctness (typically by HTML escaping) and to prevent XSS and related attacks (typically by sanitizing any untrusted parts if they can not be unescaped to plain text). + +Before deploying charts, please review this **checklist** to ensure your usage is safe: + +| APIs | Potential Risks and Suggestions | +| ------|------------------ | +| **option [tooltip.formatter](${optionPath}tooltip.formatter)**<br>· `formatter` allows HTML string or DOM elements input, which are later rendered directly inside the tooltip, where XSS risks need to be considered.<br>(exceptions): A string directly set to the `formatter` is treated as a simple template for later combining with data internally. [tooltip.renderMode: 'richText'](${optionPath}tooltip.renderMode) is another level of templating syntax for styling. Both of them are internally implemented and safe from injection.<br><br>**option [toolbox.feature.dataView.optionToContent](${optionPath}toolbox.feature.dataView.optionToContent)**<br>**option [toolbox.feature.dataView.title](${optionPath}toolbox.feature.dataView.title)**<br>**option [toolbox.feature.dataView.lang](${optionPath}toolbox.feature.dataView.lang)**<br>· The `tooltip.dataView` panel is fully rendered in HTML. Certain parts of the HTML string are allowed to be customized via these APIs. | XSS risks should be consi dered. In most cases, HTML escaping alone is sufficient. But if any unescaped parts originate from untrusted sources, more measures are required (e.g., sanitization, sandboxing).<br><br>See section ["Passing Raw HTML Safely"](best-practices/security#passing_raw_html_safely) for safe usage recommendations. | +| **option [tooltip.extraCssText](${optionPath}tooltip.extraCssText)**<br>· `extraCssText` accepts a raw CSS style string for later directly appending to `tooltipEl.style.cssText`(via the DOM API).<br>(exceptions): this option is not applicable when [tooltip.renderMode: 'richText'](${optionPath}tooltip.renderMode).<br> | Safe if the input comes from trusted sources; otherwise, a careful assessment is required.<br><br>See section ["Passing inline CSS Safely"](best-practices/security#passing_inline_css_safely) for details. | +| **option [title.link](${optionPath}title.link)**<br>**option [title.sublink](${optionPath}title.sublink)**<br>**option [series-treemap.data.link](${optionPath}series-treemap.data.link)**<br>**option [series-sunburst.data.link](${optionPath}series-sunburst.data.link)**<br>· They accept raw URLs directly for these links. | Safe if the input comes from trusted sources; otherwise, XSS risks should be considered.<br><br>See section ["Passing Raw URLs Safely"](best-practices/security#passing_raw_urls_safely) for safe usage recommendations. +**option [toolbox.feature.saveAsImage.name](${optionPath}toolbox.feature.saveAsImage.name)**<br>**option [toolbox.feature.saveAsImage.type](${optionPath}toolbox.feature.saveAsImage.type)**<br>**option [title[0].text](${optionPath}title.text)**<br>· The download filename is assembled by `{name}.{type}` without validation or sanitization. If `name` is not provided, `title[0].text` (if any) has historically been used instead, although this usage is not recommended. | See section ["Passing Download Filename Safely"](best-practices/security#passing_download_filename_safely) for safe usage recommendations. | +| All JS-function inputs (callbacks) | This is generally not a concern, unless special requirements involve untrusted code.<br><br>See section ["Passing JS Function Safely"](best-practices/security#passing_js_function_safely) for details. | + + +## Passing Raw HTML Safely [[[#passing_raw_html_safely]]] + +Section ["Security Boundaries and Checklist"](best-practices/security#security_boundaries_and_checklist) have listed the APIs that accept raw HTML directly. Untrusted HTML may lead to XSS and related attacks, so additional processing is required before passing content to ECharts. Several commonly used mitigation approaches -- "HTML Escaping", "Sanitization", "Sandboxing" are described below. In most cases, "HTML Escaping" is sufficient, except when unescaped content comes from untrusted sources. + +### HTML Escaping [[[#passing_raw_html_safely_html_escaping]]] +HTML escaping is always necessary for data before assembling it to an HTML string -- not only for security, but also for the basic correctness of display. + +A typical and simplest HTML escaping implementation is these character conversions: +``` +'&' => '&' +'<' => '<' +'>' => '>' +'"' => '"' +"'" => '' +``` +It removes the functionality from the markup characters, thereby closing the attack vector for code injection (e.g., `<script>...</script>`), regardless of whether the content is trusted or untrusted. + +Other approaches, like using DOM API `.textContent = `, can also escape HTML. + +In most use cases, untrusted content (e.g., user-provided text) is only used for display as plain text, while markup tokens (i.e., parts not meant to be escaped, such as HTML tags or attributes) are fully controlled by the application owner and therefore trusted. In this scenario, HTML escaping alone is an effective and simple way to prevent from XSS, as lone as all untrusted content is properly escaped. + +### Sanitization [[[#passing_raw_html_safely_sanitization]]] + +Some use cases require untrusted markup tokens to be interpreted as actual markup. For example, text from a database may include styling or functional tags (e.g., `<em>`, `<a href="...">`) that are meant to be interpreted rather than displayed as plain text. Another example is that users or untrusted sources are allowed to provide HTML templates that define structures and styles, which are later combined with data content to produce the final renderable HTML and passed to ECharts. + +In these cases, the security risks are heightened. Sanitization can be applied to mitigate those risks, provided that no embedded JS and CSS code is allowed to execute. A sanitizer filters HTML content based on predefined whitelists -- for example, removing `<script>` and `<style>` blocks, `<link>` elements, inline CSS, event handler attributes such as `onclick`, and URLs using `javascript:` protocol. It's recommended to use a well-maintained and widely adopted sanitizer rather than writing your own regex or manual string manipulations. + +Sanitization may be enforced on the client-side, on the server-side, or both, depending on the product requirements and threat model. For example, concerning content that originates from client (e.g., submitted by users), relying only on client-side sanitization is insufficient because an attacker can bypass the client and submit crafted payloads directly to the server. For instance, an online visual editor lets users compose posts in a WYSIWYG fashion, where users can choose from several built-in HTML snippets/templates or JS-functions (e.g., for [tooltip.formatter](${optionPath}#tooltip.formatter) or [label.formatter](${optionPath}#series-scatter.label.formatter)). If the selected or generated HTML text or JS-function text are sent from client to server and persisted to the database without any additional handling, an attacker can simulate a network request to inject malicious code. Later, when those options are retrieved and passed to [chart.setOption()](${apiPath}echartsInstance .setOption), the malicious code will execute. There are some recommended mitigations for this case: ++ Persist only reference (IDs) to this built-in snippets/tempates or JS-functions, not raw code supplied by client. ++ If user-provided snippets are allowed for expressiveness (beyond built-in selections), some third-party string templating libraries may be introduced to preventing injection. ++ If user-provided snippets must allow HTML (beyond the approaches above), enforce strict server-side sanitization or validation before persisting. This should include removing all JS, CSS, and other potentially unsafe content. Additionally, consider using a sandboxed iframe to limit the potential impact of any remaining security issues. + +Achieving sufficient security through sanitization is sometimes not easy. It requires proper configurations, must be kept up to date with browers changes, and often needs to be combined with other defense mechanisms to be "safe enough" for most real-world use cases. HTML is extremely complex -- the more features are allowed in untrusted content, the more potential attack vectors are introduced. + +### Sandboxing [[[#passing_raw_html_sandboxing]]] + +If executing untrusted code is required, or other measures are considered insufficient, a sandboxed iframe can provide a higher level of security, as used by services like JSFiddle and CodePen. + + +## Passing inline CSS Safely [[[#passing_inline_css_safely]]] + +Although CSS safety issues is covered by the discussion about HTML safety (see section ["Passing Raw HTML Safely"](best-practices/security#passing_raw_html_safely)), this section focuses especially the APIs that only accept inline CSS strings (those that modify `style` attribute via the DOM API `.style.cssText =`), which are listed in section ["Security Boundaries and Checklist"](best-practices/security#security_boundaries_and_checklist). + +If the inline CSS strings come entirely from trusted sources (e.g., they are part of your application), security considerations are minimal -- this is also the most common case. + +Otherwise, untrusted CSS can lead to attacks. Some widely adopted HTML sanitizers support CSS sanitization, but may remove all CSS by default, since sanitizing CSS properly is quite complex. Therefore, accepting untrusted CSS requires meticulous assessment base on the specific use case. + + +## Passing Raw URLs Safely [[[#passing_raw_urls_safely]]] + +Although URL safety issues is covered by the discussion of HTML safety (see section ["Passing Raw HTML Safely"](best-practices/security#passing_raw_html_safely)), this section focuses especially the APIs that only accept URL strings, which is listed in section ["Security Boundaries and Checklist"](best-practices/security#security_boundaries_and_checklist). + +If the URL strings are entirely from trusted sources (e.g., they are part of your application), security considerations are minimal. + +Otherwise, untrusted URL strings can lead to attacks, for example, by using protocols such as `javascript:` to execute malicious code. Therefore, before passing them to ECharts, sanitization should be enforced, typically by validating the protocol against a specified whitelist. + + +## Passing Download Filename Safely [[[#passing_download_filename_safely]]] + +Currently, only the [saveAsImage](${optionPath}toolbox.feature.saveAsImage) feature accepts an input as a filename. This input can be considered safe if it originates from trusted sources, does not exceed the length limit, and contains exclusively ASCII alphabetic characters. + +Otherwise, although modern browsers have significantly improved their handling of unsanitized download filenames (e.g., path traversal sequences `../`, `..\\` are stripped, and special characters are correctly handled), some risks still remain, including the inconsistent behaviors with reserved characters and length limitations. Furthermore, the behavior of older clients or browsers is unclear and less robust. Therefore, sanitization or preprocessing are required for these untrusted inputs. + + +## Passing JS Function Safely [[[#passing_js_function_safely]]] + +ECharts options (i.e., the input to [chart.setOption()](${apiPath}echartsInstance.setOption)) are primarily declarative, but some options accept JS-function (callbacks) to provide greater expressiveness and flexibility. Examples include [label.formatter](${optionPath}#series-scatter.label.formatter), [axisTick.interval](xAxis.axisTick.interval), and similar. In most use cases, these JS-function options are part of the source code of the application itself and thus fully trusted, so no security risk is introduced. Review Comment: - Reemove redundant `#` from the link: `${optionPath}#series-scatter.label.formatter` -> `${optionPath}series-scatter.label.formatter` - Incorrect link for the `axisTick.interval` option. It should be `${optionPath}xAxis.axisTick.interval` ########## contents/en/best-practices/security.md: ########## @@ -0,0 +1,97 @@ +# Security + +## Overview + +ECharts aims to provide rich and flexible visualization capabilities. Although the vast majority of its APIs do not require special security considerations, sereval APIs are exceptions. For example, the option `tooltip.formatter` accepts a raw HTML string, allowing full control over the component's content and layout; the option `title.link` uses the provided URL string directly without automatic sanitization. While this flexibility is powerful, security risks may arise if the input comes from untrusted sources. These APIs are listed below, along with suggestions on how to use these features safely. + +Any security issues can be reported to [[email protected]](mailto:[email protected]) . + + +## Security Boundaries and Checklist [[[#security_boundaries_and_checklist]]] + +ECharts focuses on visualization logic. It assumes that inputs are trusted, and does not automatically sanitize them. In fact, ECharts itself can not properly sanitize inputs, as there are no universal sanitization rules that applies to all use cases. However, ECharts should clearly identify which APIs (especially ECharts options) require security-related preprocessing or considerations in specific use cases. Given the large number of ECharts options, preprocess all inputs in every case would be impractical and unnecessary. + +ECharts renders using Canvas or SVG, except for several special components that allow HTML rendering (e.g., [toolip](${optionPath}tooltip), [dataView](${optionPath}toolbox.feature.dataView)). ECharts APIs accept Non-JS-function inputs and JS-function inputs. JS-function inputs are intended to be execute. Most non-JS-function inputs (e.g., plain text provided to be rendered) are treated as data only, and are inherently prevented from code evaluation and execution. Therefore, they generally do not require sanitization from malicious code. However, several APIs allow embeding potential unsafe content (for example, raw HTML or raw URLs) into the page. These APIs are powerful but vulnerable to Cross-Site Scripting (XSS) and related attacks if the inputs originate from untrusted sources. + +**Generally speaking, if no untrusted content is involved, these injection vulnerabilities will not arise.** Untrusted content refers to content that originates from a source that can not be fully controlled, or that can be modified or injected by users or external systems. Developers must assume it unsafe to use directly in HTML, CSS and JS. For example, content is untrusted if it is produced by users or received from a client. However, handling user-provided content is often unavoidable. For example, when rendering user data fetched from a database inside an HTML-based `tooltip` through a customized formatter, additional processing is required to ensure correctness (typically by HTML escaping) and to prevent XSS and related attacks (typically by sanitizing any untrusted parts if they can not be unescaped to plain text). + +Before deploying charts, please review this **checklist** to ensure your usage is safe: + +| APIs | Potential Risks and Suggestions | +| ------|------------------ | +| **option [tooltip.formatter](${optionPath}tooltip.formatter)**<br>· `formatter` allows HTML string or DOM elements input, which are later rendered directly inside the tooltip, where XSS risks need to be considered.<br>(exceptions): A string directly set to the `formatter` is treated as a simple template for later combining with data internally. [tooltip.renderMode: 'richText'](${optionPath}tooltip.renderMode) is another level of templating syntax for styling. Both of them are internally implemented and safe from injection.<br><br>**option [toolbox.feature.dataView.optionToContent](${optionPath}toolbox.feature.dataView.optionToContent)**<br>**option [toolbox.feature.dataView.title](${optionPath}toolbox.feature.dataView.title)**<br>**option [toolbox.feature.dataView.lang](${optionPath}toolbox.feature.dataView.lang)**<br>· The `tooltip.dataView` panel is fully rendered in HTML. Certain parts of the HTML string are allowed to be customized via these APIs. | XSS risks should be consi dered. In most cases, HTML escaping alone is sufficient. But if any unescaped parts originate from untrusted sources, more measures are required (e.g., sanitization, sandboxing).<br><br>See section ["Passing Raw HTML Safely"](best-practices/security#passing_raw_html_safely) for safe usage recommendations. | +| **option [tooltip.extraCssText](${optionPath}tooltip.extraCssText)**<br>· `extraCssText` accepts a raw CSS style string for later directly appending to `tooltipEl.style.cssText`(via the DOM API).<br>(exceptions): this option is not applicable when [tooltip.renderMode: 'richText'](${optionPath}tooltip.renderMode).<br> | Safe if the input comes from trusted sources; otherwise, a careful assessment is required.<br><br>See section ["Passing inline CSS Safely"](best-practices/security#passing_inline_css_safely) for details. | +| **option [title.link](${optionPath}title.link)**<br>**option [title.sublink](${optionPath}title.sublink)**<br>**option [series-treemap.data.link](${optionPath}series-treemap.data.link)**<br>**option [series-sunburst.data.link](${optionPath}series-sunburst.data.link)**<br>· They accept raw URLs directly for these links. | Safe if the input comes from trusted sources; otherwise, XSS risks should be considered.<br><br>See section ["Passing Raw URLs Safely"](best-practices/security#passing_raw_urls_safely) for safe usage recommendations. +**option [toolbox.feature.saveAsImage.name](${optionPath}toolbox.feature.saveAsImage.name)**<br>**option [toolbox.feature.saveAsImage.type](${optionPath}toolbox.feature.saveAsImage.type)**<br>**option [title[0].text](${optionPath}title.text)**<br>· The download filename is assembled by `{name}.{type}` without validation or sanitization. If `name` is not provided, `title[0].text` (if any) has historically been used instead, although this usage is not recommended. | See section ["Passing Download Filename Safely"](best-practices/security#passing_download_filename_safely) for safe usage recommendations. | Review Comment: `title[0].text` looks unnecessary, and it is enough to use `title.text`. ########## contents/en/best-practices/security.md: ########## @@ -0,0 +1,97 @@ +# Security + +## Overview + +ECharts aims to provide rich and flexible visualization capabilities. Although the vast majority of its APIs do not require special security considerations, sereval APIs are exceptions. For example, the option `tooltip.formatter` accepts a raw HTML string, allowing full control over the component's content and layout; the option `title.link` uses the provided URL string directly without automatic sanitization. While this flexibility is powerful, security risks may arise if the input comes from untrusted sources. These APIs are listed below, along with suggestions on how to use these features safely. + +Any security issues can be reported to [[email protected]](mailto:[email protected]) . + + +## Security Boundaries and Checklist [[[#security_boundaries_and_checklist]]] + +ECharts focuses on visualization logic. It assumes that inputs are trusted, and does not automatically sanitize them. In fact, ECharts itself can not properly sanitize inputs, as there are no universal sanitization rules that applies to all use cases. However, ECharts should clearly identify which APIs (especially ECharts options) require security-related preprocessing or considerations in specific use cases. Given the large number of ECharts options, preprocess all inputs in every case would be impractical and unnecessary. + +ECharts renders using Canvas or SVG, except for several special components that allow HTML rendering (e.g., [toolip](${optionPath}tooltip), [dataView](${optionPath}toolbox.feature.dataView)). ECharts APIs accept Non-JS-function inputs and JS-function inputs. JS-function inputs are intended to be execute. Most non-JS-function inputs (e.g., plain text provided to be rendered) are treated as data only, and are inherently prevented from code evaluation and execution. Therefore, they generally do not require sanitization from malicious code. However, several APIs allow embeding potential unsafe content (for example, raw HTML or raw URLs) into the page. These APIs are powerful but vulnerable to Cross-Site Scripting (XSS) and related attacks if the inputs originate from untrusted sources. + +**Generally speaking, if no untrusted content is involved, these injection vulnerabilities will not arise.** Untrusted content refers to content that originates from a source that can not be fully controlled, or that can be modified or injected by users or external systems. Developers must assume it unsafe to use directly in HTML, CSS and JS. For example, content is untrusted if it is produced by users or received from a client. However, handling user-provided content is often unavoidable. For example, when rendering user data fetched from a database inside an HTML-based `tooltip` through a customized formatter, additional processing is required to ensure correctness (typically by HTML escaping) and to prevent XSS and related attacks (typically by sanitizing any untrusted parts if they can not be unescaped to plain text). + +Before deploying charts, please review this **checklist** to ensure your usage is safe: + +| APIs | Potential Risks and Suggestions | +| ------|------------------ | +| **option [tooltip.formatter](${optionPath}tooltip.formatter)**<br>· `formatter` allows HTML string or DOM elements input, which are later rendered directly inside the tooltip, where XSS risks need to be considered.<br>(exceptions): A string directly set to the `formatter` is treated as a simple template for later combining with data internally. [tooltip.renderMode: 'richText'](${optionPath}tooltip.renderMode) is another level of templating syntax for styling. Both of them are internally implemented and safe from injection.<br><br>**option [toolbox.feature.dataView.optionToContent](${optionPath}toolbox.feature.dataView.optionToContent)**<br>**option [toolbox.feature.dataView.title](${optionPath}toolbox.feature.dataView.title)**<br>**option [toolbox.feature.dataView.lang](${optionPath}toolbox.feature.dataView.lang)**<br>· The `tooltip.dataView` panel is fully rendered in HTML. Certain parts of the HTML string are allowed to be customized via these APIs. | XSS risks should be consi dered. In most cases, HTML escaping alone is sufficient. But if any unescaped parts originate from untrusted sources, more measures are required (e.g., sanitization, sandboxing).<br><br>See section ["Passing Raw HTML Safely"](best-practices/security#passing_raw_html_safely) for safe usage recommendations. | +| **option [tooltip.extraCssText](${optionPath}tooltip.extraCssText)**<br>· `extraCssText` accepts a raw CSS style string for later directly appending to `tooltipEl.style.cssText`(via the DOM API).<br>(exceptions): this option is not applicable when [tooltip.renderMode: 'richText'](${optionPath}tooltip.renderMode).<br> | Safe if the input comes from trusted sources; otherwise, a careful assessment is required.<br><br>See section ["Passing inline CSS Safely"](best-practices/security#passing_inline_css_safely) for details. | +| **option [title.link](${optionPath}title.link)**<br>**option [title.sublink](${optionPath}title.sublink)**<br>**option [series-treemap.data.link](${optionPath}series-treemap.data.link)**<br>**option [series-sunburst.data.link](${optionPath}series-sunburst.data.link)**<br>· They accept raw URLs directly for these links. | Safe if the input comes from trusted sources; otherwise, XSS risks should be considered.<br><br>See section ["Passing Raw URLs Safely"](best-practices/security#passing_raw_urls_safely) for safe usage recommendations. +**option [toolbox.feature.saveAsImage.name](${optionPath}toolbox.feature.saveAsImage.name)**<br>**option [toolbox.feature.saveAsImage.type](${optionPath}toolbox.feature.saveAsImage.type)**<br>**option [title[0].text](${optionPath}title.text)**<br>· The download filename is assembled by `{name}.{type}` without validation or sanitization. If `name` is not provided, `title[0].text` (if any) has historically been used instead, although this usage is not recommended. | See section ["Passing Download Filename Safely"](best-practices/security#passing_download_filename_safely) for safe usage recommendations. | +| All JS-function inputs (callbacks) | This is generally not a concern, unless special requirements involve untrusted code.<br><br>See section ["Passing JS Function Safely"](best-practices/security#passing_js_function_safely) for details. | + + +## Passing Raw HTML Safely [[[#passing_raw_html_safely]]] + +Section ["Security Boundaries and Checklist"](best-practices/security#security_boundaries_and_checklist) have listed the APIs that accept raw HTML directly. Untrusted HTML may lead to XSS and related attacks, so additional processing is required before passing content to ECharts. Several commonly used mitigation approaches -- "HTML Escaping", "Sanitization", "Sandboxing" are described below. In most cases, "HTML Escaping" is sufficient, except when unescaped content comes from untrusted sources. + +### HTML Escaping [[[#passing_raw_html_safely_html_escaping]]] +HTML escaping is always necessary for data before assembling it to an HTML string -- not only for security, but also for the basic correctness of display. + +A typical and simplest HTML escaping implementation is these character conversions: +``` +'&' => '&' +'<' => '<' +'>' => '>' +'"' => '"' +"'" => '' +``` +It removes the functionality from the markup characters, thereby closing the attack vector for code injection (e.g., `<script>...</script>`), regardless of whether the content is trusted or untrusted. + +Other approaches, like using DOM API `.textContent = `, can also escape HTML. + +In most use cases, untrusted content (e.g., user-provided text) is only used for display as plain text, while markup tokens (i.e., parts not meant to be escaped, such as HTML tags or attributes) are fully controlled by the application owner and therefore trusted. In this scenario, HTML escaping alone is an effective and simple way to prevent from XSS, as lone as all untrusted content is properly escaped. + +### Sanitization [[[#passing_raw_html_safely_sanitization]]] + +Some use cases require untrusted markup tokens to be interpreted as actual markup. For example, text from a database may include styling or functional tags (e.g., `<em>`, `<a href="...">`) that are meant to be interpreted rather than displayed as plain text. Another example is that users or untrusted sources are allowed to provide HTML templates that define structures and styles, which are later combined with data content to produce the final renderable HTML and passed to ECharts. + +In these cases, the security risks are heightened. Sanitization can be applied to mitigate those risks, provided that no embedded JS and CSS code is allowed to execute. A sanitizer filters HTML content based on predefined whitelists -- for example, removing `<script>` and `<style>` blocks, `<link>` elements, inline CSS, event handler attributes such as `onclick`, and URLs using `javascript:` protocol. It's recommended to use a well-maintained and widely adopted sanitizer rather than writing your own regex or manual string manipulations. + +Sanitization may be enforced on the client-side, on the server-side, or both, depending on the product requirements and threat model. For example, concerning content that originates from client (e.g., submitted by users), relying only on client-side sanitization is insufficient because an attacker can bypass the client and submit crafted payloads directly to the server. For instance, an online visual editor lets users compose posts in a WYSIWYG fashion, where users can choose from several built-in HTML snippets/templates or JS-functions (e.g., for [tooltip.formatter](${optionPath}#tooltip.formatter) or [label.formatter](${optionPath}#series-scatter.label.formatter)). If the selected or generated HTML text or JS-function text are sent from client to server and persisted to the database without any additional handling, an attacker can simulate a network request to inject malicious code. Later, when those options are retrieved and passed to [chart.setOption()](${apiPath}echartsInstance .setOption), the malicious code will execute. There are some recommended mitigations for this case: Review Comment: There are redundant `#` in the generated links. `${optionPath}#` -> `${optionPath}` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
