drawio 中 CryptoJS AES 加密裁剪包(aes.min.js 4.2.0)的构建、安全升级与实时协作集成解析
前端图形学【免费下载链接】drawiodraw.io is a JavaScript, client-side editor for general diagramming.项目地址https://gitcode.com/gh_mirrors/dr/drawio点击查看免费下载本指南围绕 drawio 仓库中 src/main/webapp/js/cryptojs/aes.min.js 及其 README 展开说明这份裁剪版 CryptoJS 4.2.0 rollup的来龙去脉如何从 npm 包手工打包、drawio 用它加密实时协作realtime collaboration消息的哪些环节、为什么从 3.1.2 升级到 4.2.0以及升级后对线上格式兼容性、安全边界和构建流程的影响。读完你将掌握该文件的构建命令、DrawioFileSync中 AES/MD5 的调用链、CSPRNG 探测与失败关闭fail-closed机制以及替换/升级该库时需要注意的验收清单。1. aes.min.js 是什么一份被裁剪的 CryptoJS 4.2.0aes.min.js并不是 CryptoJS 的完整发行版而是一份Trimmed CryptoJS 4.2.0 rollup只包含六个模块按依赖顺序拼接后压缩core enc-base64 md5 evpkdf cipher-core aes这个模块清单并非 drawio 自己拍脑袋定的而是CryptoJS 上游为aes.js声明的依赖列表。由于 CryptoJS 4.x 移除了 3.x 时代内置的rollups/目录drawio 只能从 npm 包手工拼接出对应 rollup再交给 Closure Compiler 做压缩。值得强调的是这份裁剪是克制的——README 明确列出没有包含的内容没有 SHA / HMAC / PBKDF2 / RC4 / Rabbit / DES 等其余算法没有 CBC 之外的密码模式没有 Pkcs7 之外的填充方式。也就是说这个文件只为满足 drawio 实时协作场景下一个 AES-CBC OpenSSL 口令 KDF MD5的最小需求而存在避免了把整个 CryptoJS 全家桶塞进前端包体。2. 从 npm 包手工构建 rollup完整命令README 给出了可复现的构建流程在本地临时目录执行需要 JDK 环境运行 Closure Compiler# 1) 拉取指定版本的 crypto-js npm 包并解包 npm pack crypto-jsversion tar xzf crypto-js-version.tgz # 2) 按上游 aes.js 的依赖顺序拼接六个模块文件生成 rollup.js for f in core enc-base64 md5 evpkdf cipher-core aes; do cat package/$f.js; echo; done rollup.js # 3) 用 Closure CompilerSIMPLE_OPTIMIZATIONS、ES5 输入输出压缩 java -jar etc/build/compiler.jar --compilation_level SIMPLE_OPTIMIZATIONS \ --language_in ECMASCRIPT5 --language_out ECMASCRIPT5 \ --js rollup.js --js_output_file rollup.min.js产出rollup.min.js之后再从当前仓库的aes.min.js文件头复制署名头attribution header并更新版本号即可。README 特别提醒如果未来 CryptoJS 上游改变了aes.js的依赖列表应当跟随新的依赖清单重新裁剪而不是沿用本文件这份清单——这说明该 rollup 的模块集合是与上游声明强绑定的。从产物内容可以印证上述过程aes.min.js文件头即为CryptoJS v4.2.0、MIT 许可及Trimmed rollup: core enc-base64 md5 evpkdf cipher-core aes的说明随后是各模块以 UMD 包装形式依次出现的压缩代码包括enc.Hex、enc.Latin1、enc.Utf8、WordArray.randomRNG 探测逻辑、MD5、EvpKDF、CBC模式、Pkcs7填充、OpenSSL格式/KDF以及最后注册的v.AES。3. drawio 用它做什么AES 加密实时协作消息 MD5 生成通道密钥3.1 AES 加解密DrawioFileSync.objectToString / stringToObjectdrawio 对 CryptoJS 的主要使用点是DrawioFileSync的序列化/反序列化方法DrawioFileSync.prototype.objectToStringDrawioFileSync.js先把消息对象JSON.stringify自 PROTOCOL 7 起JSON 直接交给 pakodeflateRaw压缩再 Base64旧版本先 URI-encode 再压缩JSON 引号和非 ASCII 字符会被膨胀最多 3 倍编码耗时占大头文件格式Graph.compress不受影响若指定了maxLength且压缩后数据超限返回null让调用方丢弃超大载荷加密只会让数据变大且 CryptoJS 的 base64 编码器会为超大载荷逐字符建数组而抛RangeError当存在通道密钥this.key且CryptoJS可用时调用CryptoJS.AES.encrypt(data, this.key).toString()完成加密。DrawioFileSync.prototype.stringToObjectDrawioFileSync.js先CryptoJS.AES.decrypt(data, this.key).toString(CryptoJS.enc.Utf8)解密再 pakoinflateRaw解压并兼容旧客户端写入的 URI-encoded 载荷以%开头则decodeURIComponent最后JSON.parse。这两个方法同时被P2P 协作路径复用在 P2PCollab.js 中发送加密消息时直接构造msg {bytes: sync.objectToString(msg), data: aes}data: aes是为了让旧服务器不会丢弃消息接收侧则用sync.stringToObject(msg.bytes)还原P2PCollab.js。3.2 字符串密钥触发 OpenSSL KDFEvpKDF关键机制是objectToString传入的this.key是字符串而非 32 字节的二进制密钥。CryptoJS 检测到字符串密钥时会走口令派生路径——用 OpenSSL KDFEvpKDF默认 MD5 迭代 1 轮见 rollup 内v.kdf.OpenSSL实现从口令派生出 AES 密钥与 IV其中8 字节 salt 来自WordArray.random。由此引出本文后面要讲的安全边界AES 密钥实际派生自通道密钥channel key即this.key一个共享秘密salt 只是公开的、按 OpenSSLSalted__格式明文前置在密文上的随机数。3.3 MD5 用途通道密钥派生README 列出的 MD5 使用点与源码一一对应OneDriveFile.prototype.getChannelKeyOneDriveFile.js以创建时间戳 创建者用户 ID拼接后取CryptoJS.MD5(...).toString()作为通道密钥nextcloud插件plugins/nextcloud.js以instanceId id拼接取CryptoJS.MD5(...).toString()README 提到的monday插件同样依赖该库的 MD5。对照之下Google Drive 的DriveFile.prototype.getChannelKeyDriveFile.js不做哈希而是直接读取存储的自定义属性key——README 特意点出这一差异说明并非所有存储后端都走 MD5 派生。4. 为什么是 4.2.0一次由安全公告驱动的升级4.1 3.1.2 的两个问题升级前 drawio 用的是 CryptoJS 3.1.2其问题有两个弱随机源3.1.2 的WordArray.random用Math.random()播种seed被 Dependabot 标记为GHSA-rg76-677x-56q9/CVE-2026-71851alert #310弱 KDF 默认值3.1.2 存在弱 PBKDF2 默认值问题issue #1624.2.0 一并修复。4.x 系列改用crypto.getRandomValues作为熵源4.2.0 同时清掉了 #162。4.2 真实暴露面salt 碰撞而非密钥恢复README 对风险边界做了精确界定不夸大、也不轻描淡写在 3.1.2 下不安全的 RNG 只用于生成KDF salt而 salt 在 OpenSSLSalted__格式下以明文形式前置在密文中本来就是要公开的因此实际风险是salt 碰撞导致同一通道密钥下 (key, IV) 复用而不是 AES 密钥被恢复——因为 AES 密钥派生自通道密钥共享秘密与 RNG 无关。换言之升级 4.2.0 消除的是同一共享密钥 弱随机 salt 造成 (key, IV) 复用这类密码学使用风险。4.3 确定性输出逐字节比对在升级前仓库对库产生的所有确定性输出都做了与 3.1.2 的逐字节比对覆盖MD5Utf8 / Latin1 / Hex / Base64 编码器EvpKDF固定 salt 下的 AES双向跨版本解密3.1.2 加密 → 4.2.0 解密反之亦然。这保证了升级不是换了把锁任何依赖这些确定性输出的存量数据与在线会话都保持可读。5. 行为差异与失败关闭fail-closed机制5.1 没有原生 crypto 时从静默降级到显式抛错3.1.2在无原生加密native crypto的环境下静默回退到Math.random()4.2.0直接抛出Native crypto module could not be used to get secure random number.需要澄清的是只有加密受此影响——AES.decrypt和MD5从不触碰 RNG解密与哈希在无 CSPRNG 环境下依然可用。5.2 RNG 探测链与不安全上下文4.2.0 的WordArray.random按以下顺序探测可用熵源见aes.min.js中core模块的探测代码self.crypto → globalThis.crypto → window.msCrypto → global.crypto → require(crypto)并且getRandomValues在不安全上下文insecure contexts即普通 HTTP 部署下也可用所以纯 HTTP 部署的 drawio 实例不受影响。5.3 可被覆盖的window.crypto与isEncryptionAvailable兜底虽然探测链覆盖广README 仍指出一个可攻击点window.crypto是一个可配置configurable的访问器属性嵌入页面或插件可以用Object.defineProperty替换它从而让前两步探测失效进而使整个探测链失败。drawio 对此的兜底实现是DrawioFileSync.prototype.isEncryptionAvailableDrawioFileSync.js若没有通道密钥或没有 CryptoJS直接返回true本就不加密谈不上风险否则做一次CryptoJS.lib.WordArray.random(8)探测成功则缓存encryptionAvailable true抛错则缓存false并通过EditorUi.logError记录文件 ID 经哈希后才进日志避免原始文件 ID 泄漏结果每会话只探测一次缓存于静态属性DrawioFileSync.encryptionAvailable不重载页面不会改变。探测结果为假时objectToString会抛出No CSPRNG for realtime encryptionDrawioFileSync.js实时同步被保持关闭。README 解释了为什么不能回退到明文接收方仍持有通道密钥会尝试解密而得到乱码且明文载荷会落入缓存——因此发不出去比发出去但谁都读不了更安全。这就是典型的失败关闭设计宁可让带密钥通道的实时协作不可用也不发一条接收方读不了、缓存却能读的消息。6. 构建集成与替换方式6.1 逐字拼接永不重编译构建阶段aes.min.js会被concat逐字拼进base.min.js且不会再经过 Closure 编译。这意味着文件内的 UMD 包装和require(crypto)引用不会经过 Closure 处理避免被优化器改写破坏替换该库就是一次直接的文件替换straight file swap不需要改动构建链。开发模式下Devel.js 通过mxscript(drawDevUrl js/cryptojs/aes.min.js)直接按开发 URL 加载该文件生产构建则把内容拼入base.min.js。此外该文件也出现在 service-worker.js 的预缓存清单中js/cryptojs/aes.min.js说明其作为运行时静态资源参与 Service Worker 预缓存。6.2 线上格式兼容4.2.0 与 3.1.2 可互通由于 EvpKDF / OpenSSL 格式在版本间未变4.2.0 的 rollup 在线上是升级兼容的同一协作会话里一个 3.1.2 客户端和一个 4.2.0 客户端依然能互相读取对方的消息。这是第 4.3 节双向跨版本解密验证在真实场景中的意义。6.3 升级/替换验收清单可操作建议结合 README 与源码替换或升级aes.min.js时应至少验证模块集合确认新版本aes.js的依赖声明是否仍是core, enc-base64, md5, evpkdf, cipher-core, aes有变化就跟随新清单确定性输出MD5、四种编码器Utf8/Latin1/Hex/Base64、EvpKDF、固定 salt 的 AES 结果与旧版本逐字节一致双向互操作旧版本加密 → 新版本解密、新版本加密 → 旧版本解密均通过CSPRNG 行为确认无原生 crypto 时抛错、有getRandomValues含 HTTP 不安全上下文时可用并确认isEncryptionAvailable探测/缓存逻辑仍能覆盖构建产物替换后检查base.min.js中拼接内容、service-worker.js预缓存清单与开发模式Devel.js加载路径是否同步。7. 小结aes.min.js是 drawio 实时协作加密链路中一个小而关键的组件它以裁剪 rollup 的方式只引入 CryptoJS 的 AES-CBCOpenSSL KDF 口令派生与 MD5为DrawioFileSync的消息加密和OneDriveFile/nextcloud等后端的通道密钥派生提供基础升级到 4.2.0 修复了 3.1.2 弱随机源Math.random()与弱 KDF 默认值问题同时通过逐字节比对保证线上格式兼容而isEncryptionAvailable的失败关闭设计则确保在 CSPRNG 被嵌入页或插件破坏时实时协作宁可不启动也不发送任何接收方无法解密的消息。理解这份文件的构建命令、使用点与安全边界是排查 drawio 实时同步加密问题、或在其基础上做定制升级的前提。赞分享前端图形学【免费下载链接】drawiodraw.io is a JavaScript, client-side editor for general diagramming.项目地址https://gitcode.com/gh_mirrors/dr/drawio点击查看免费下载相关推荐N_m3u8DL-RE 流媒体下载教程10 分钟装好并跑通第一条 m3u8/MPD 下载命令N_m3u8DL RE 流媒体下载教程10 分钟装好并跑通第一条 m3u8/MPD 下载命令 N_m3u8DL RE 是一款免费开源的跨平台流媒体下载工具专CLI音视频LangChain Go 30 分钟入门从 0 到 1 构建带记忆的 AI 对话助手LangChain Go 30 分钟入门从 0 到 1 构建带记忆的 AI 对话助手 LangChain Golangchaingo是一个用 Go 编写的人工智能大模型AI AgentRAG后端解密前端加密黑盒从CryptoJS源码看AES算法实现解密前端加密黑盒从CryptoJS源码看AES算法实现 你是否曾在开发中调用 CryptoJS.AES.encrypt 时疑惑明明传入的是字符串为何能输出密码学上一篇Spotify下载器终极指南快速免费下载Spotify音乐并保存完整元数据下一篇三步解锁百度网盘高速下载告别龟速拥抱光速创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考