MutationObserver 防篡改的核心是监控画布容器、识别非平台变更并毫秒还原:仅监听 #canvas-root 等语义化锚点,启用 childList/subtree/关键 attributes 观察,回调中三层判定非法操作,修复时先断开再还原最后重连。
用 MutationObserver 给低代码平台画布加防篡改锁,核心不是“锁死 DOM”,而是盯住画布容器、识别非平台自身发起的变更、并安全还原——它不阻止篡改发生,但能让非法拖拽、脚本注入、控制台误操作在毫秒内被识别和拦截。
只锁定画布根容器,避开组件树噪音
低代码平台的画布通常有稳定锚点,比如
、
或
。不要监听
或整个
,否则会混入组件预览更新、属性面板联动、实时协作同步等合法变更,导致误报率飙升。
优先用
获取目标,若画布异步加载,可配合
延迟初始化
避免依赖动态 class(如
),用语义化
属性或固定 ID 锚定
若平台支持多画布(如页签式设计区),需为每个画布单独实例化 observer,不共用配置
配置精简观察项,覆盖典型篡改动作
画布篡改集中在三类行为:拖入非法组件(script/iframe)、删除关键节点(如根容器、绑定锚点)、修改样式隐藏控件(
、
覆盖)。只需启用以下组合:
—— 捕获控制台执行
或插件注入悬浮窗
—— 确保子组件内部改动也被捕获(例如在按钮组件内插入伪造
)
—— 只盯影响渲染与绑定的关键属性,跳过
、
等无关变更
禁用
—— 画布不承载法律文本,无需监听文本节点;禁用
—— 不需比对旧值,省开销
回调中做三层轻量判定,不盲目响应
每次回调收到的是批量记录,里面可能夹杂平台自身触发的更新(如组件重渲染)。必须快速过滤出真正可疑的操作:
第一层归属判断:
第二层类型筛选:若
,遍历
,用
匹配非法节点
第三层意图识别:若
且
,检查
或
异常(如
且非平台设定值)
安全修复:断开 → 还原 → 重连
一旦确认篡改,修复动作必须隔离、可逆、不递归:
先调用
,防止
或
再次触发回调
优先还原原始状态:若画布初始化时已缓存
,可用
;若只改样式,用
替代全量重写
修复完成后,再调用
恢复监控
对高频场景(如用户频繁拖拽组件),加简单节流:记录上一次修复时间戳,50ms 内同类变更直接忽略
#canvas-root[data-role="design-canvas"].lc-canvasdocument.body#appdocument.querySelector('#canvas-root')requestIdleCallbackcanvas-123abcdata-display: nonez-indexchildList: truecanvasRoot.appendChild(adDiv)subtree: truespanattributes: true + attributeFilter: ['class', 'style', 'data-lc-id', 'hidden']idtitlecharacterDataattributeOldValueif (!canvasRoot.contains(mutation.target) && mutation.target !== canvasRoot) returntype === 'childList'addedNodesnode.matches('script, iframe, [id^="ad-"], [class*="taboola"]')type === 'attributes'attributeName === 'style'getComputedStyle(target).display === 'none'zIndex> 9999observer.disconnect()target.remove()el.style.display = ''canvasRoot.dataset.originalHTMLcanvasRoot.innerHTML = originalHTMLel.style.removeProperty('display')observer.observe(canvasRoot, config)