从 npm 投毒事件思考,我写了一个基于 FUSE 的 macOS 文件守护工具 Shield - V2EX
请不要在回答技术问题时复制粘贴 AI 生成的内容
vone

从 npm 投毒事件思考,我写了一个基于 FUSE 的 macOS 文件守护工具 Shield

  •  
  •   vone 23h 2m ago 868 views

    Shield - macOS File Access Protection

    最近一段时间发生了多次投毒事件,恶意代码随意读取 ~/.ssh 、.npmrc 、等机密文件然后静默上传。整个过程中系统没有任何阻拦。机密文件的泄露后导致的密钥轮换工作操作了不少额外的工作和风险,所以最近 Vibe Coding 了一个简单的工具,来尝试解决这个问题。

    下面简单介绍一下开发的思路和实现原理,更详细内容可以阅读 https://www.npmjs.com/package/@yangch/shieldREADME.md

    它做了什么

    Shield 是一个基于 FUSE (用户空间文件系统) 的 macOS 命令行工具,能让你指定的敏感文件在被任何进程读取时,弹出一个原生对话框问你“允许还是拒绝”。

    技术实现细节

    核心流程只有三步:文件重定向 → FUSE 拦截 → 用户授权。

    1.存储与重定向

    当你执行 shield add ~/.ssh/id_rsa 时:

    原始文件被移动到 /usr/local/var/shield/storage/ 下对应的路径

    原位置创建一个符号链接,指向 FUSE 挂载点 /usr/local/var/shield/mount/ 下的相同路径

    之后,任何对 ~/.ssh/id_rsa 的读写都会经过这个 FUSE 挂载点,由守护进程接管。

    2.FUSE 层拦截

    Shield 内部运行一个 shield-daemon ,它通过 FUSE 实现了一个简单的文件系统。当进程执行 open() 调用试图打开受保护的文件时,内核将该调用转发到守护进程的 FUSE 处理函数。

    这里使用的是 fuse-t (推荐,无需内核扩展,支持 macOS 13+),也可以回退到 macFUSE 。整个拦截发生在用户空间,不影响系统稳定性。

    3.用户授权对话框

    守护进程收到访问请求后,通过调起一个原生 macOS 对话框,选择 Allow 会放行本次读取,并缓存授权 10 秒。在这 10 秒内,同一文件再次被读不会重复弹窗,避免频繁打扰。选择 Deny 则直接返回错误给调用方,调用方会收到类似 Operation not permitted 的结果,文件内容不会被泄露。

    所有授权/拒绝决定都会被写入日志,事后可以审计。 Shield Access Dialog

    Access Denied 4.后台驻留

    Shield 作为 launchd 服务运行,开机自启。用户可以通过 shield start/stop/status 管理守护进程,不占用 Dock 或菜单栏,静默运行。

    安装与使用

    # 先安装 fuse-t (推荐,无 kext ) brew install fuse-t # 安装 Shield sudo npm install -g @yangch/shield # 初始化并启动服务 sudo shield install # 添加要保护的文件 sudo shield add ~/.ssh/id_rsa sudo shield add ~/.aws/credentials sudo shield add ~/.npmrc # 查看守护列表 shield list # 移除保护(会还原文件到原始位置) sudo shield remove ~/.ssh/id_rsa 

    之后只要你在使用系统,任何对受保护文件的读取都会弹窗询问。

    一些说明

    1 、只支持 macOS ,推荐使用 fuse-t (用户空间,无需批准内核扩展),Windows 暂时还没有支持。

    2 、目前只拦截了文件的访问,但是并未对原文件做加密,只能阻拦有针对性的机密文件获取。

    3 replies    2026-05-12 14:16:46 +08:00
    yangg
        1
    yangg  
       22h 49m ago   1
    这个是个不错的方向
    xylophone21
        2
    xylophone21  
       22h 42m ago   1
    比如 ~/.aws/credentials 文件,
    - 如果使用 aws cli 进程或者 skill 的脚本来读取, 则是合法的,配置后自动授权
    - 如果其他进程来读取,比如 AI 直接读, 临时专项的脚本等, 则弹出授权

    原理上可以实现吗
    vone
        3
    vone  
    OP
       22h 29m ago
    @xylophone21 取决于 FUSE 的实现方式。
    1 、在 Linux 、Windows 上读取访问进程名是没问题的。
    2 、在 MacOS 上如果是 macFUSE 可以读取访问进程名,但是 macFUSE 的安装需要通过内核扩展,目前安装比较麻烦。目前我推荐使用的 fuse-t 是基于 NFS 协议实现的,无法获取访问进程名。
    3 、在 MacOS 上也可以通过 ESF 框架实现,但是这个权限 Apple 官方审核很严格,只针对大型安全公司开放。
    4 、在 MacOS 上推荐使用 fuse-t
    所以结论就是:MacOS 不太行,其他系统可以。
    About     Help     Advertise     Blog     API     FAQ     Solana     3608 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 36ms UTC 04:46 PVG 12:46 LAX 21:46 JFK 00:46
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86