macOS 上开源应用提示“已损坏”或“无法验证开发者”的完整解析

问题现象

从 GitHub Releases 下载并安装 Deskflow v1.26.0 或 InputLeap 后,双击打开时 macOS 弹出两个不同的错误提示:

情况一 — “已损坏”:

“Deskflow” is damaged and can’t be opened. You should move it to the Trash.

情况二 — “无法验证”:

“InputLeap” cannot be opened because the developer cannot be verified. macOS cannot verify that this app is free of malware.

这两个提示看起来吓人,很多人第一反应是下载的文件损坏了,或者是木马病毒。但实际上 这是 macOS Gatekeeper 的安全机制在起作用,与文件完整性无关。

本文从技术底层分析这两个提示的区别、产生原因,并提供修复方法。


一、macOS 应用安全模型:Gatekeeper 与代码签名

要理解这个问题,需要先了解 macOS 的三个安全层级:

1.1 Quarantine(隔离标记)

当你通过浏览器、下载管理器(如 Free Download Manager)、AirDrop 或 iMessage 获取应用时,macOS 会自动给文件加上一个扩展属性:

1
com.apple.quarantine

这个属性存储了下载来源的元数据:

1
2
$ xattr -l /Applications/Deskflow.app
com.apple.quarantine: 0183;6a272425;Free Download Manager;5442B527-28B9-40AE-A280-FA934495E716

格式为:<flags>;<timestamp>;<来源应用>;<UUID>。有了这个标记,macOS 知道这个应用是从外部下载的,需要在首次启动时进行安全检查。

1.2 Code Signing(代码签名)

所有 macOS 应用都应该有数字签名。签名有两种方式:

签名类型 含义 典型用途
Development(开发签名) 用本地生成的证书签名 Xcode 调试,仅本机可用
Developer ID(分发签名) 用 Apple 签发的开发者证书签名 公开发布,需要 Apple 公证

通过 codesign 命令可以查看签名信息:

1
2
3
4
$ codesign -dvvv /Applications/Deskflow.app
Signature=adhoc # <-- 自签名,非 Apple 开发者签名
CodeDirectory v=20400 flags=0x2(adhoc)
TeamIdentifier=not set # <-- 无团队标识

1.3 Notarization(公证)

即使应用有 Developer ID 签名,macOS 还会在后台将应用的哈希值发送给 Apple 服务器验证是否包含已知恶意软件——这个过程叫公证(notarization)。公证成功的应用会得到一个盖章(ticket),嵌入到应用中。


二、为什么 Deskflow 和 InputLeap 会报错

2.1 共同根因:Adhoc 签名 + Quarantine 标记

这两个开源项目都是社区贡献者用 adhoc(自签名) 方式打包的。所谓 adhoc 签名,就是在编译时由链接器(linker)打上的一个本地签名:

1
2
3
4
5
# Deskflow 的签名
flags=0x2(adhoc)

# InputLeap 的签名 —— 甚至更弱
flags=0x20002(adhoc, linker-signed)

linker-signed 意味着连手动 codesign 命令都没有执行,完全依赖编译器自动签名。

当应用同时满足以下两个条件时,macOS 就会拒绝启动:

  1. 有 com.apple.quarantine 属性(从外部下载)
  2. 代码签名不是 Apple Developer ID(无法联系公证服务)

运行逻辑是这样的:

1
2
3
4
5
用户双击 → 发现 quarantine 标记 → 触发 Gatekeeper 验证
→ 检查代码签名
→ 发现是 adhoc(非 Developer ID)
→ 无法联系 Apple Notary 服务
→ ❌ 拒绝启动,弹出错误

2.2 两个错误提示的细微区别

虽然根因相同,但 Deskflow 和 InputLeap 的签名质量不同,导致 macOS 给出不同等级的警告:

指标 Deskflow InputLeap
签名类型 adhoc adhoc, linker-signed
Sealed Resources 有(33个文件) 无
Info.plist 签名 已绑定 未绑定
macOS 提示 “is damaged” “cannot be verified”

“Damaged” 是更严厉的提示——macOS 认为应用内容(签名摘要与文件不匹配或未被签名覆盖)可能已被篡改。InputLeap 连 Info.plist 都没有签名覆盖,意味着理论上你可以随意修改它的 Info.plist 而不会被检测到。

2.3 为什么开源项目不解决这个问题

这背后有一个现实原因:Apple Developer Program 年费 $99。

很多开源项目没有这笔预算,或者维护者不愿意每年支付这笔费用只为给 macOS 用户一个更好的体验。即使支付了,还需要配置 CI/CD 流水线做公证(notarization),进一步增加了维护负担。

以 Deskflow 为例,GitHub 上有 相关 issue 讨论 macOS 签名问题,但因为流程复杂和费用问题,至今没有解决。


三、排查方法:一步一步验证

如果你遇到类似问题,可以用以下命令诊断:

步骤 1:检查是否有 Quarantine 标记

1
xattr -l /Applications/YourApp.app

如果输出包含 com.apple.quarantine,说明隔离标记已设置。

步骤 2:检查代码签名类型

1
codesign -dvvv /Applications/YourApp.app 2>&1 | grep -E "Signature|TeamIdentifier|flags"
  • Signature=adhoc → 自签名,大概率是问题所在
  • Signature=Developer ID Application → 有正确的分发签名
  • TeamIdentifier=not set → 无开发者团队

步骤 3:查看 Gatekeeper 评估结果

1
spctl --assess --verbose /Applications/YourApp.app

输出 accepted 表示通过(可能因为安全策略已关闭),rejected 表示被拦截。

步骤 4:检查二进制架构

1
file /Applications/YourApp.app/Contents/MacOS/*

确认是 arm64(Apple Silicon)还是 x86_64(Intel)。如果你的 Mac 是 Apple Silicon 但下载的是 Intel 版本,需要通过 Rosetta 运行,但一般不会导致 “damaged” 错误。

步骤 5:检查动态库链接

1
otool -L /Applications/YourApp.app/Contents/MacOS/YourApp

确认所有链接库都能找到。缺失的动态库也会导致启动失败,但错误提示不同(通常是”意外退出”而不是”已损坏”)。


四、修复方法

方法一:移除 Quarantine 属性(推荐)

1
sudo xattr -rd com.apple.quarantine /Applications/YourApp.app

参数说明:

  • -r:递归处理,移除所有子文件和目录的属性
  • -d:删除指定的扩展属性

执行后,macOS 就不再对该应用进行启动安全检查,可以直接打开。

方法二:通过右键菜单打开

在 Finder 中找到应用,按住 Control 键点击(或右键),选择 “打开”。在弹出的对话框中点击 “打开”,macOS 会记住这次授权,后续可以直接双击打开。

但这个方法治标不治本,下次更新后又会弹出提示。

方法三:关闭 Gatekeeper(不推荐)

1
sudo spctl --master-disable

系统偏好设置中会出现”任何来源”选项。这是最彻底的方案,但会降低系统安全性,不建议日常使用。


五、预防:如何避免再次遇到

  1. 优先从 Mac App Store 安装:经过苹果审核签名,不会有此问题
  2. 通过 Homebrew 安装:brew install deskflow——Homebrew 会处理签名和权限问题
  3. 关注项目的官方 DMG 签名:如果项目发布带 Developer ID 签名的版本,优先选择
  4. 下载后先移除隔离属性:养成习惯,下载安装后立即执行 sudo xattr -rd com.apple.quarantine /Applications/xxx.app

总结

问题 原因 解决
“已损坏,移到废纸篓” Adhoc 签名 + Quarantine 标记导致 Gatekeeper 拒绝 sudo xattr -rd com.apple.quarantine
“无法验证开发者” Linker-signed 签名 + 无公证 + Quarantine 同上
“意外退出” 架构不匹配 / 缺少动态库 file + otool -L 排查

对于 macOS 上的开源应用,”is damaged” 和 “cannot be verified” 最常见的真实原因不是文件损坏,而是没有正确的 Apple Developer ID 签名。通过移除 quarantine 属性即可解决,无需重装、无需重新下载。


参考资料

中文/EN