鸿蒙 PC Markdown 编辑器安全边界:本地优先、CSP 与受限能力

鸿蒙 PC Markdown 编辑器安全边界:本地优先、CSP 与受限能力
Markdown是文本,但预览会变成 HTML,链接和图片会产生资源请求,ArkWeb还通过 Bridge连接原生文件能力。若默认允许脚本、在线资源、任意文件和宽泛代理,本地编辑器就可能被一份恶意文档扩展成代码执行与数据访问入口。
本文基于 OhMarkdown,分析离线单文件、markdown-it禁用 HTML、DOMPurify、导出 CSP、链接阻断、ArkWeb权限收缩和 Bridge白名单。代码位于 https://gitcode.com/VON-/codex_md_oh,对应提交 3a9146e。
安全模型从不信任文档开始
用户可能打开网络下载、邮件附件、仓库 clone或他人共享的 Markdown。文件内容不可信,即使应用不联网,HTML事件、危险协议和 Bridge调用仍可能产生影响。
安全目标:源码可以显示;常用 Markdown可预览;原生 HTML默认不执行;外部资源不自动加载;链接不在 ArkWeb直接导航;Web只调用有限原生事件;导出文件带独立 CSP。
本地优先不是“没有服务器所以安全”,而是把所有能力默认关闭后按工作流开放。
Web资源完全离线
Vite用 singlefile把 JS/CSS内联到 rawfile index.html。生产测试断言没有 <script src>和外部 stylesheet。应用启动不访问 CDN,依赖供应链在构建时固定,不在运行时远程变化。
base: './'避免绝对网络路径。sourcemap关闭。离线完整既提高可用性,也减少远程脚本被替换和网络元数据泄露。
markdown-it 第一层关闭 HTML
const markdownRenderer = new MarkdownIt({
html: false,
linkify: true,
typographer: false,
breaks: false
});
html: false让 <script>、iframe、带事件属性的标签不成为活动 DOM。Markdown结构仍生成受控 HTML。不能为了兼容“Markdown内嵌 HTML”直接打开,再假设浏览器会安全处理。
如果未来支持 HTML子集,应明确标签/属性白名单并单独开关,默认仍关闭。产品“专业”不等于默认执行文档内任意代码。
DOMPurify 是最终输出边界
function sanitizeMarkdown(content: string): string {
const unsafeHtml = markdownRenderer.render(content);
return DOMPurify.sanitize(unsafeHtml, {
USE_PROFILES: { html: true },
FORBID_TAGS: [
'style',
'iframe',
'object',
'embed',
'form'
],
FORBID_ATTR: ['style']
});
}
净化发生在所有 Markdown插件生成 HTML之后。先净化源码再渲染会让插件输出绕过。禁止 style防止文档重排或隐藏应用 UI,禁止嵌入与表单缩小导航、插件和提交能力。
DOMPurify还处理事件属性和危险协议。每次升级依赖或增加插件,都要重新运行安全语料,因为输出标签集合可能变化。
允许功能也要验证
安全语料包含危险 script、javascript链接、iframe,同时包含允许相对图片。测试断言危险不存在、标题/加粗/安全图片保留。把所有 HTML删除虽然“安全”,却不是可用 Markdown预览。
任务列表插件生成 disabled input,表格生成结构,链接生成 href。净化配置必须允许必要元素,但不开放交互写回和外部导航。
链接不在 ArkWeb直接打开
preview.querySelectorAll<HTMLAnchorElement>('a')
.forEach((link) => {
link.target = '_blank';
link.rel = 'noopener noreferrer';
link.addEventListener(
'click',
(event) => event.preventDefault()
);
});
链接保持视觉与导出语义,应用内点击被阻止。noopener noreferrer为未来外部打开保留隔离。当前没有让文档把 ArkWeb导航到站点或新窗口。
后续由原生接管时,必须解析 URL scheme,只允许 http/https并显示确认;file、javascript、data和自定义协议默认拒绝。相对链接需要工作区解析,不能交浏览器自由访问文件。
ArkWeb 权限最小化
Web({
src: $rawfile('editor/index.html'),
controller: this.editorController
})
.javaScriptAccess(true)
.domStorageAccess(false)
.onlineImageAccess(false)
.fileAccess(false)
.geolocationAccess(false)
.zoomAccess(false)
JavaScript是 CodeMirror所需,其他不需要能力关闭。在线图片禁用防止打开文档自动向远端服务器发送 IP、时间和 URL。fileAccess关闭防止 Web页面直接扫描本地,文件统一由 Core File Kit授权后在原生处理。
DOM storage关闭,编辑正文不写浏览器 localStorage;恢复使用应用沙箱受控记录。geolocation与文档编辑无关。
Bridge 只暴露事件白名单
methodList: [
'onReady',
'onState',
'onChange',
'onSnapshot',
'onCommand'
]
Web不能传方法名让原生动态执行,也不能直接获得文件读写对象。onCommand只接受 new/open/save/find,原生 switch分发。onSnapshot限制五兆和整数 revision。
原生到 Web调用参数全部 JSON.stringify,防止正文或查询闭合脚本字符串。字符串返回按 JSON解码。协议边界同时解决正确性与注入。
导出 HTML 带独立 CSP
<meta http-equiv="Content-Security-Policy"
content="default-src 'none';
style-src 'unsafe-inline';
img-src data: file:;
font-src data:;
base-uri 'none';
form-action 'none'">
导出文件可能离开应用在浏览器打开,不能依赖 ArkWeb设置。default-src 'none'默认拒绝,允许内嵌样式、data/file图片和 data字体;禁止 base改变相对 URL和 form提交。
导出 title先 HTML转义,正文复用 sanitizeMarkdown。测试输入 </title><script>,断言没有脚本;危险链接不出现在 href/src。
style-src 'unsafe-inline'用于内嵌导出 CSS,是明确例外。没有 script-src允许,文档不运行脚本。
打印复用净化预览
打印先 preparePrint,确保预览由同一净化链生成,再创建 Web打印适配器。打印媒体隐藏编辑器,只显示预览。不会把原始 Markdown HTML直接交给打印系统。
大文档模式拒绝打印,避免构建巨大 DOM造成资源耗尽。安全也包括可用性攻击边界。
内容安全测试
Playwright输入 script并设置全局副作用:
const source =
'# 标题\n\n' +
'<script>' +
'window.unsafeScriptExecuted=true' +
'</script>';
断言预览 script数量0且 unsafeScriptExecuted未定义。仅检查节点不存在不够,脚本可能先执行后删除;副作用证明没有执行。
导出测试断言没有 script、javascript URI和外部 stylesheet,同时保留 h1、strong和相对图片。
安全预览界面
下图是鸿蒙 PC应用内的源码与预览工作面。预览来自 markdown-it和 DOMPurify,不是任意 HTML浏览器页面。

截图不能证明脚本未执行,自动化副作用断言与 ArkWeb权限检查才是证据。应用图满足文章的真实运行画面要求。
恢复记录与隐私
未保存正文写入应用沙箱,未加密,依赖 HarmonyOS应用隔离。日志不记录正文和 URI,内部试用不收文档内容。卸载应用会删除沙箱恢复。
高敏感场景未来可提供关闭恢复、系统密钥加密和安全删除策略,但必须评估密钥丢失与性能。默认恢复与隐私之间需要产品明确说明。
依赖与供应链
markdown-it-task-lists固定版本,package-lock固定实际树,CI使用 npm ci和 --ignore-scripts。依赖升级单独评审渲染输出和安全测试。
长期需要 SBOM、许可证和漏洞扫描。不能仅因为运行时离线就忽略构建依赖风险,恶意包可以在构建时进入单 HTML。
DoS 与规模边界
五兆以上关闭 Markdown预览、字数和恢复全文;文件读取上限二十兆;目录每层两千项;恢复 JSON有字节上限。规模限制防止恶意或异常文件耗尽内存。
正则表达式仍可能灾难性回溯,超大 Replace All也可能建立大量对象。这是尚未完全解决的可用性安全风险,应增加数量上限和安全正则策略。
当前边界
没有外部链接安全打开流程;相对图片解析有限;恢复记录未加密;未建立 SBOM与自动漏洞扫描;正则 DoS仍需处理;导出 file图片权限在不同浏览器需验证;插件体系尚未设计沙箱。
安全回归的发布红线
任何测试发现 script执行、javascript协议保留、ArkWeb加载外部 CDN、Bridge出现未审查方法、文件访问被放宽或恶意文档造成稳定崩溃,都应停止功能发布。修复必须补最小语料和自动断言,不能只改配置后人工看一遍。
安全报告区分源码预览、导出 HTML、打印和未来插件,因为它们运行环境不同。一个入口净化通过不代表另一入口自动安全。发布候选还要扫描最终 HAP,而不是只审查源码配置。
结语
OhMarkdown安全边界由多层组成:离线单文件、禁用原生 HTML、最终 DOMPurify、链接阻断、ArkWeb权限关闭、窄 Bridge、导出 CSP和规模限制。任何一层都不是万能,组合后把不可信 Markdown限制在阅读与编辑所需范围。
鸿蒙 PC编辑器的本地优先必须落实为默认不联网、不扫描文件、不执行文档代码,并且每次新增能力都明确打开了哪一扇门、由什么测试守住。
更多推荐




所有评论(0)