ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

claude-obsidian 六机制归档防御全解:符号链接、穿越与内容寻址

claude-obsidian 六机制归档防御全解:符号链接、穿越与内容寻址 claude-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 Karpathys LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidianclaude-obsidian 是把任意来源归档进 Obsidian Markdown 知识库的第二大脑工具。它的归档入口capture直接接收外部文件为此构建了一条覆盖词法预检、符号链接审计、文件名卫生、预算硬限、内容寻址与并发冲突的六机制防御链。本文按一个文件掉进 inbox 之后的生命周期逐机制拆解其代码实现与错误码。问题场景一个无害的 inbox 文件能带来什么归档链路是文件进入inbox/被内容寻址复制进.raw/captured/不可变仓库再被加工成带出处的笔记。入口是敞开的攻击面也随之敞开。设想两个场景在库目录里把inbox/notes做成指向系统目录的符号链接再顺着它归档库外文件。只校验路径字符串的复制工具对此毫无察觉。库里已有inbox/Note.md再丢进一个inbox/note.md。在不区分大小写的文件系统上两者是同一个文件——为前者算好的审批与哈希会被静默套用到后者。更常见的还有第三种两个进程同时归档同一个库队列文档被写到一半。claude-obsidian 的应对不是单点打补丁而是一条覆盖IO 之前、之中、之后的完整链路安全边界在 SECURITY.md 中声明为一组防御性不变量。claude-obsidian 的路径词法闸门没碰磁盘就被拒绝词法闸门拦的是根本不值得碰磁盘的一类路径绝对路径、..段、反斜杠、控制字符、以及a/../b这类未规范化写法。配置侧由_validate_relative_directory校验统一抛INVALID_CONFIG_PATH事务侧写入路径更严_normalize_vault_path还要检查路径串的 NFC 形态与 240 字节可移植上限逐项抛INVALID_WRITE_PATH、NONCANONICAL_UNICODE_PATH、WRITE_PATH_TOO_LONG。词法检查有一个天然盲区它只看字符串不看文件系统。词法上完美的a/b.md若a实际是个符号链接路径依旧穿越。所以assert_within在真实文件系统上再做一次包含性检查解析符号链接后确认落点仍在库内否则抛PATH_OUTSIDE_VAULT。为什么两道都做词法检查零 IO是最便宜的快速失败resolve()检查依赖文件系统状态、代价高。便宜的放前面过滤昂贵的放后面兜底。这道闸门仍拦不住验证之后目录被换成符号链接那是下一道检查的事。️ claude-obsidian 的符号链接审计从 inbox 到 raw 仓库逐段拒绝符号链接必须在使用处检查原因是 TOCTOUT1 时刻不是符号链接的结论不能支撑 T2 时刻的写入。claude-obsidian 因此在每次使用前的瞬间重查每一段覆盖四个位置位置检查入口错误码源根目录inbox / raw 根_allowed_source_path、discover_filesSOURCE_ROOT_SYMLINK源路径中的任意目录段_allowed_source_pathSOURCE_SYMLINK.raw内容寻址仓库_planned_destinationRAW_STORE_SYMLINK事务写入路径的每一段_safe_vault_pathSYMLINK_WRITE_PATH最彻底的是_allowed_source_path先用resolve()确认源文件的真实落点再沿路径逐段is_symlink()检查——即使源文件本身干净只要它穿过一个别名目录进入收件箱同样被SOURCE_OUTSIDE_INBOX拦下。事务侧的_safe_vault_path对写入路径用lstat()做同样的逐段检查中间段若不是真实目录也拒绝。它仍然拦不住名字合法但语义含糊的情况Note.md与note.md各自通过全部检查却可能在某些文件系统上指向同一个文件。claude-obsidian 的文件名卫生与 casefold 别名消歧文件名攻击常藏在细节里。_validate_filename一次拦下控制/格式字符Unicode C 类、首尾空格、以点或空格结尾的名字、Windows 保留名CON、COM1、NUL等、非 NFC 的 Unicode 名称——命中即抛UNSAFE_FILENAME。写入侧还有一组配套规则_assert_portable_write_path其中两处细节值得注意:是 NTFS 备用数据流命名对目录枚举不可见别名审计永远看不见它以点或空格结尾的名字会在 Win32 系统调用边界被截断从而静默别名到截断形态。两者都被UNPORTABLE_WRITE_PATH覆盖。该规则只作用于新建写入、不碰存量文件保证历史遗留的奇怪但合法文件依旧可读。最后一环是别名消歧_assert_no_existing_portable_alias枚举目标目录的全部兄弟项把每个名字经_portable_name_keyNFC casefold归一成可移植身份发现不同名但同身份即抛CASEFOLD_PATH_ALIAS。目录条目过多时则以VAULT_DIRECTORY_LIMIT中止审计而非静默放行——审计要么做完要么失败没有中间态。claude-obsidian 的预算硬限失败即中止零落盘哪怕单文件的名称与路径都干净一次丢进来五万个文件仍是资源耗尽问题。批次在进入任何 IO 之前先过CaptureBudget的硬限max_items: int 100 max_total_bytes: int 256 * 1024 * 1024 max_file_bytes: int 64 * 1024 * 1024_preflight_sources对整批做预检超过 100 个文件抛COUNT_BUDGET_EXCEEDED单文件超 64 MiB 抛FILE_BUDGET_EXCEEDED总量超 256 MiB 抛TOTAL_BUDGET_EXCEEDED。source_identity计算摘要时还会对实际读到的字节再计一次——即使 stat 显示不大以真实读入为准。捕获队列文档同样有上限8 MiB / 4096 条MAX_QUEUE_BYTES、MAX_QUEUE_ENTRIES见 capture.py。选失败即中止而非能收多少收多少是刻意的部分批次会让库留下半套文件错误状态难以回退立即失败只留下一个确定性错误码库保持原样。事务层另有自己的总量上限MAX_TRANSACTION_TOTAL_BYTES128 MiB见 transaction.py两层构成双闸门。claude-obsidian 的内容寻址校验名字就是哈希预算闸门管住多少下一个问题是是什么。归档的核心动作是把源文件复制成SHA-256 摘要.扩展名存入.raw/captured/。名字即哈希于是白赚两层校验。其一是身份指纹。source_identity以O_NOFOLLOW打开文件按 1 MiB 分块边读边算 SHA-256读前读后比对(dev, ino, size, mtime_ns)四元组并用文件描述符上的fstat交叉验证——计算中途文件被替换直接抛SOURCE_CHANGED。你归档的永远是你看到的那份内容。其二是重复归档防篡改_find_existing_capture发现同摘要的旧副本时重新校验字节内容寻址文件名字对、内容不对即说明仓库被外部改写抛IMMUTABLE_SOURCE_CONFLICT。为什么不用大小加 mtime 做弱校验mtime 可伪造、大小易碰撞哈希对比才是终局。原始资料区由此变成只创建、永不修改——已有副本必须与摘要完全一致否则整个操作失败。claude-obsidian 的队列锁与所有权令牌冲突回滚不静默吞单文件可信了同一个库却可能被多进程同时操作。捕获队列由目录型锁CaptureQueueLock保护锁目录原子创建失败即已有持有者持有者写入含pid、主机名与随机 token 的 owner 记录释放前回读 token 比对——不一致即抛QUEUE_LOCK_OWNERSHIP_LOST见 release 流程。这个回读比对防的是经典的锁偷换第三方删掉锁并重建原持有者若只按路径操作就会误删别人的锁。死锁恢复则保守处理确认持有进程已死且锁已超龄才清理清理动作本身还要复查锁身份未变。事务层再以预检哈希 持久日志 原子替换 确定性回滚兜底每个写入携带expected_hashes预期值回滚时验证目标未被换过否则抛ROLLBACK_TARGET_CHANGED进程中途崩溃可由recover_incomplete见 transaction.py安全恢复。所有冲突都收敛进CaptureConflict错误家族每个冲突一个确定性错误码——没有静默失败。边缘补充claude-obsidian 的 URL 侧 SSRF 闸门本地归档之外外部 URL 来源同样被锁死。validate_https_url只接受 HTTPS 并拒绝空白、控制字符与反斜杠_validate_public_host以URL_PRIVATE_HOST拦掉localhost、.internal等保留域与回环/链路本地网段连0x7f.0.0.1这类能绕过ipaddress的十六进制 IP 写法也在拦截范围内validate_redirect_chain把跳转链逐跳对照显式白名单越界抛REDIRECT_HOST_FORBIDDEN。外部动作经plan_external_action只能生成惰性计划用户明确同意才执行。验证与上手复现 claude-obsidian 归档入口的错误码克隆仓库git clone https://gitcode.com/GitHub_Trending/cl/claude-obsidian再按 docs/install-guide.md 初始化一个独立知识库。最快的复现入口是跑归档测试pytest tests/test_capture.py符号链接、预算、队列锁场景都有覆盖想亲眼看到SOURCE_SYMLINK在临时知识库的inbox/里建一个指向库外的符号链接再触发一次归档批次即可。归档事务与回滚的规则细节另见 skills/wiki/references/operation-transactions.md。 claude-obsidian 归档防御文件速查文件职责claude_obsidian/capture.py归档前置校验、文件名卫生、预算、队列锁与 URL 校验claude_obsidian/transaction.py写入路径规范化、别名审计、原子写与回滚恢复claude_obsidian/paths.py库根解析与路径包含性检查SECURITY.md安全边界与防御性不变量声明docs/install-guide.md安装与知识库初始化指南skills/wiki/references/operation-transactions.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 Karpathys LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表