claude-obsidian:恶意文件闯进 Obsidian 知识库会撞上哪些检查——归档入口四道关口完整拆解
【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian + Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathy's LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian
claude-obsidian 是一个把任意资料变成本地知识库的工具:丢给它文件或链接,它会归档进你的 Obsidian 知识库并整理链接,逐渐长成一张互连的 Markdown 知识图谱。但这个归档入口也是"外部输入"直接接触你文件系统的唯一位置,全部安全设计都集中在这里。下面跟着一个可疑文件走完它的旅程,看它一路上会过哪些关口。
威胁面速写:攻击者对一份文件能做什么
先站到攻击者一边想五件事:
- 路径把戏:用
../或符号链接逃离知识库目录,够到库外的文件; - 同名混淆:在不区分大小写的系统上,拿
Note.md与NOTE.MD钻检查的空子; - 资源耗尽:一批塞进海量文件或几个 GB 的大块头,吃满磁盘;
- 并发捣乱:多个进程同时操作同一个库,写坏的覆盖别人的;
- 借道 URL:把归档链接指向内网地址,让工具替自己探内网。
后面的关口,就是逐条掐断这五条路。
第一道关口:纸面审查——磁盘还没被碰到
这一关的所有判断都不接触磁盘:文件在内存里只是一段字符串,读完字符串就能定生死。
- 路径词法:绝对路径、反斜杠、
./..段、a/../b这类未规范化写法一律拒收;文件名要求 NFC 形态(Unicode 的统一编码形式),长度不超 240 字节。配置侧见_validate_relative_directory,事务层的_normalize_vault_path更严。 - 文件名卫生:
_validate_filename拦下控制字符、零宽字符、首尾带空格的怪名字,以及CON、NUL这类 Windows 保留名。 - 预算硬限:
CaptureBudget是批次的"入场券"——单批最多 100 个文件,单文件 64 MB、整批 256 MB;队列文档 8 MB、4096 条封顶。越线即失败,FILE_BUDGET_EXCEEDED、TOTAL_BUDGET_EXCEEDED这类错误码确定性地报出来,没有"再试一次也许行"。
为什么放在最前?因为零成本。就像查快递先看面单,最离谱的包裹根本不用开箱就能识别,IO 的开销和副作用都省了。
第二道关口:走上真实文件系统——路径为什么要查两遍
词法干净,就真的安全吗?未必。一个叫wiki的目录,实体可能是一条指向系统别处的符号链接(一种"快捷方式",指向另一个真实位置)。
于是系统在真实文件系统上再查一遍:
- 符号链接四处拦截:收件箱根目录报
SOURCE_ROOT_SYMLINK,inbox 内目录条目报SOURCE_SYMLINK,.raw存储报RAW_STORE_SYMLINK,事务写入路径的每一段报SYMLINK_WRITE_PATH。 - 中间目录逐段走查:
_allowed_source_path不只看终点,只要源文件途经某段被换成别名目录进入收件箱,同样以SOURCE_OUTSIDE_INBOX拦下。 - 包含性复核:
assert_within把符号链接全部解析后确认落点仍在库内,否则PATH_OUTSIDE_VAULT。 - 同名陷阱:
_assert_no_existing_portable_alias写入前枚举目录里的兄弟项,只要 NFC + casefold(忽略大小写的归一化)后撞名,就抛CASEFOLD_PATH_ALIAS。
串成一个攻击看:攻击者在 inbox 里放一条指向~/.ssh的链接,工具刚想顺着走,逐段检查先报警,包含性检查再兜一刀,链路两步之内就断了。
第三道关口:进不可变仓库——指纹当文件名的账本
文件过了前两关,核心动作才开始:内容寻址复制。说白了,就是拿文件内容的指纹当文件名,把源文件以<SHA-256>.<扩展名>的形式复制进.raw/captured/。
- 身份指纹:
source_identity算 SHA-256 时,同时比对读取前后的 inode、大小和修改时间。文件若在这几秒间被调包,SOURCE_CHANGED立刻抛出——落库的是校验那一刻真实存在的字节。 - 重复归档再对账:
_find_existing_capture碰到同指纹的旧副本会重新逐字节校验。旧副本和自己名字里的指纹对不上,说明仓库被人从外部动过,IMMUTABLE_SOURCE_CONFLICT一报,整个操作失败。
原始资料区因此变成一本只能往后记、不许涂改的账:旧记录必须和指纹严丝合缝,多一分少一分都过不了。
第四道关口:多进程同场——谁的写不能压过谁的
两个进程同时操作同一个库,谁说了算?claude-obsidian 的答案是:锁、令牌,加可恢复的事务。
- 队列锁
CaptureQueueLock靠原子创建锁目录实现:创建失败说明已有持有者;持有者在 owner.json 里写下pid、主机名和随机 token,释放前回读核对 token,防止锁被人中途顶替,被顶替则报QUEUE_LOCK_OWNERSHIP_LOST。 - 死锁恢复很克制:确认持有进程已不存在、锁又明显超龄,才敢回收;动手前再核对一次锁的身份没变。
- 事务兜底:claude_obsidian/transaction.py 里每次写入先记预期哈希,日志持久化,落盘走原子替换;回滚前再核对目标文件的指纹,期间被换过就报
ROLLBACK_TARGET_CHANGED,中断也能安全续做。 - 每次冲突都有姓名:全部收敛进
CaptureConflict错误家族,报错响亮明确,不玩静默失败。
加餐:归档源是 URL 时,边界画在哪
攻击面换成网络,防线跟着换位置:
validate_https_url只认 HTTPS,其余协议直接拒;- 私有与本地主机一律
URL_PRIVATE_HOST:localhost、169.254.*网段、.internal后缀,乃至各种数字编码 IP 的花式写法; - 重定向一旦跳出白名单域名即中断;
- 外部动作只允许生成"惰性计划",用户明确点头之前,一个字节都不会发出去。
上手体验:克隆一个库,跑通完整旅程
体验路径很短:克隆仓库后运行初始化脚本,一个独立知识库即生成。安装细节见 docs/install-guide.md,归档事务的规则另在 skills/wiki/references/operation-transactions.md 有说明。
仓库地址:https://gitcode.com/GitHub_Trending/cl/claude-obsidian
跑起来之后,归档进来的资料最终会组织成可以反复查询的图谱与画布:
收尾:威胁、拦截手段与错误码速查
| 威胁 | 拦截手段 | 错误码 |
|---|---|---|
| 路径穿越 | 词法校验 + 包含性复核 | PATH_OUTSIDE_VAULT |
| 符号链接逃逸 | 四处逐段拒绝 | SOURCE_SYMLINK、SYMLINK_WRITE_PATH |
| 同名文件混淆 | casefold 别名枚举 | CASEFOLD_PATH_ALIAS |
| 资源耗尽 | 批次预算硬限 | FILE_BUDGET_EXCEEDED |
| 源文件归档中被调包 | 前后元数据对账 | SOURCE_CHANGED |
| 仓库副本被改写 | 内容寻址逐字节再校验 | IMMUTABLE_SOURCE_CONFLICT |
| 并发抢锁 | owner token 回读 | QUEUE_LOCK_OWNERSHIP_LOST |
| 回滚期间目标被换 | 预检哈希 + 指纹复核 | ROLLBACK_TARGET_CHANGED |
| URL 探测内网 | HTTPS 白名单 + 私有主机拒绝 | URL_PRIVATE_HOST |
安全策略本身则声明在 SECURITY.md。从文件名读入到锁释放,每一步都留下可对账的痕迹——一个把"文件归你所有"当原则的项目,用这种方式守住外部内容越界的瞬间。
【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian + Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathy's LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考