The Wisdom of Quinn代码签名避坑清单:6个Gatekeeper拦截与签名崩溃原因 📅 发布时间:2026/8/23 12:46:46 👁 浏览次数: The Wisdom of Quinn代码签名避坑清单6个Gatekeeper拦截与签名崩溃原因【免费下载链接】The-Wisdom-of-QuinnShare and Enjoy®项目地址: https://gitcode.com/gh_mirrors/th/The-Wisdom-of-QuinnThe Wisdom of QuinnThe-Wisdom-of-Quinn收录了 Apple DTS 资深工程师 Quinn “The Eskimo!” 的代码签名、分发与调试经验文章。本文提炼出 macOS 代码签名Code Signing开发中最常踩的 6 个坑Gatekeeper 拦截的 4 大诱因与代码签名崩溃SIGKILL, Code Signature Invalid的排查路径附自检步骤和对照清单帮你在发布前快速定位问题、避免用户信任流失 ️一图看懂6 大签名避坑速查表#坑点典型症状一句话解法1悬空加载命令路径Dangling rpathGatekeeper 直接拦截 App别关闭库校验清掉指向应用外的 rpath2公证票据缺失或哈希不匹配系统日志出现ticket not available核对公证日志中的 cdhash 与 sha2563签名封印被破坏a sealed resource is missing or invalid签后别动文件文件名坚持用 ASCII4权限未授权 / entitlements 文件格式异常启动即崩溃无线程回溯规范化 plist逐项比对 Profile 授权5签名证书不受信任errSecInternalComponent、unable to build chain补中间证书、检查过期与信任设置6滥用--deep签名嵌套代码被同一套参数签名由内向外逐个签名并脚本化坑 1悬空 rpath 是 Gatekeeper 拦截的头号原因Gatekeeper 的职责是只放行受信任的软件。项目明确指出最常见的拦截原因是悬空加载命令路径dangling load command path而它的根源几乎都指向一个动作——关闭了库校验Library Validation。为什么悬空库校验开启时Gatekeeper 会跳过对 Mach-O 镜像的深度检查因为库校验本身就防住了动态库冒充攻击一旦你用com.apple.security.cs.disable-library-validation权限把它关掉Gatekeeper 就必须逐层严查。此时如果某个 rpath 指向了应用包之外的目录比如开发机的/Users/xxx/Work等于给恶意同名框架留了入口Gatekeeper 立刻拦截。如何识别在系统日志中搜索rPathCmd或loadCmd关键字形如failed on rPathCmd ... (rpath resolved to: (path not found))的条目就是元凶。注意悬空 rpath 不一定在主可执行文件里也可能藏在深层嵌套的动态库中——逐个镜像检查才能找全。如何避开✅ 首选方案保留库校验开启。只有当你的 App 需要加载第三方开发者的插件时才关闭它而那正是问题的来源。✅ 必须关闭时调整构建系统剔除所有指向应用包外的LC_RPATH路径若是第三方 SDK 带来的推动供应商修复或最后手段是自行修改加载命令后重新签名。⚠️ 小提醒Swift 包管理器SPM为 Mac 命令行工具构建时会自动注入 rpath天然容易触发此问题。 原文Resolving Gatekeeper Problems Caused by Dangling Load Command Paths坑 2已公证却被拦核对 cdhash 票据Gatekeeper 要求应用完成公证Notarisation。未公证的 App 会被一个笼统的用户级提示拦截。判断是否属于公证问题看系统日志中是否有这类条目process: syspolicyd message: ticket not available: 2/2/8b7410713591e6c79ea98f0132136f0faa55d22a那串十六进制数字就是问题代码的cdhash代码目录哈希可用codesign -d -vvv反查它是 App 本身还是某个被引用的动态库。已公证仍被拦的三种可能公证日志里查不到这个 cdhash —— 说明这段代码根本没提交给公证服务、或公证后被替换、或打包方式让公证服务看不见它比如动态库没被收录哈希不匹配Hash Mismatch—— 公证日志里的 sha256 与你实际分发的文件对不上。特别注意zip 压缩包不支持票据装订stapling如果你分发的是 zip 却拿装订后的文件去比对一定是文件拿错了磁盘镜像.dmg未签名导致无法确认一致性 —— 建议改用签名的 dmg 分发。避坑动作清单✅ 公证后保留一份 stapler 修改前的文件副本方便日后比对✅ 用 Fetching the Notary Log 的方法拉取公证日志把 cdhash 与 sha256 逐项对一遍✅ 发布前按 Testing a Notarised Product 做端到端验证。 原文Resolving Gatekeeper Problems · Notarisation Fundamentals坑 3签完名又动了文件封印直接被破坏任何在签名之后对 App 包的修改都会破坏代码签名封印。先用验证命令自检codesign -v -vvv --strict --deep MyApp.app-vvv会精确告诉你哪里破了例如同时出现file added / file modified / file missing三类提示说明资源在签名后被动过。一个反直觉的坑压缩解压本身就能破坏签名。原文案例中一个含文件名Zoë Schrödinger.txt的 App 用 Finder 压缩再解压后签名立即失效且报错同时显示该文件被添加和被移除。真相是 Unicode 归一化差异解压过程把ë从预组合形式转成了分解形式文件名在字节层面变了——尽管肉眼看不出任何差别。Apple 的代码签名实现没有忽略归一化差异r. 68829319。避坑口诀✅ 包内文件名、字符串资源坚持使用ASCII✅ 签名放在分发打包流程的最后一步之后不再触碰✅ 涉及打包传输时注意保留扩展属性与签名可参考 Extended Attributes and Zip Archive。坑 4启动即崩溃——entitlements 未授权与格式陷阱代码签名崩溃的特征异常信息是EXC_CRASH (SIGKILL (Code Signature Invalid))。确认启动崩溃的标志是线程回溯完全不可用Backtrace not available说明代码一行都没跑就被可信执行系统拦下了。此时证据在系统日志里典型条目会直接点名Unsatisfied entitlements: com.apple.xxx。最常见的两种原因① 声明了受限权限却未被描述文件授权。用codesign -d --entitlements -倒出应用的 entitlements与embedded.provisionprofile的载荷逐项比对应用声明的每个受限权限Profile 里必须有对应授权要么去掉多余的声明要么修改 App ID 能力并重建 Profile 来补授权。② entitlements plist 的格式陷阱。用文本编辑器手改 plist 极易引入不可见错误注释、非 Unix 换行符等奇怪格式都可能让可信执行系统直接拦截——先规范化再签名plutil -convert xml1key 值内部多一个换行或前导空格如\ncom.apple.security.cs.disable-library-validation权限名就完全变掉了系统会把它当成未授权的受限权限App 被静默拦截。加分认知大多数开发者看不到这类崩溃因为 Xcode 的自动签名会提前发现并修复这些问题。如果你在用 Xcode 却绕开了自动签名请认真考虑回归。 原文Resolving Code Signing Crashes on Launch坑 5签名证书不受信任——过期、缺中间证书、信任被改钥匙串访问中签名证书应当显示绿色勾 This certificate is valid。如果不是先排除三大常见原因① 证书过期。钥匙串显示红色叉与 certificate is expiredcodesign报could not be found in the keychainsecurity find-identity显示CSSMERR_TP_CERT_EXPIRED。更新证书即可证书没过期时顺手检查 Mac 的系统时钟。② 信任链缺中间证书。症状是codesign报unable to build chain to self-signed rooterrSecInternalComponent且security find-identity中身份存在但无效。最省事的修复从 Apple PKI 页面把Apple Intermediate Certificates 列表全部下载并导入钥匙串多装中间证书无害也可按 Issuer Name 中的 Common Name Organizational Unit 精确匹配单个中间证书。验证时用证书助手选Generic仅证书链验证选 Code Signing 反而会让助手临时下载缺失证书、掩盖问题。③ 信任设置被人为覆盖。对链上每张证书注意同一证书可能在多个钥匙串中有多份副本检查 Trust 区域第一个下拉应为 Use System Defaults其余应为 no value specified全部恢复默认。⚠️ 两个易错细节比对证书是否被 Profile 授权时认准Serial Number而不是 Common Name——两个签名身份完全可能共用相同名称而只有其一在 Profile 列表里另外 Developer ID 代码带安全时间戳证书过期后旧应用仍可运行判断过期时别被表象误导。 原文Fixing an untrusted code signing certificate坑 6--deep签名——看似省事实为地雷项目里有一篇专门的文章叫--deepConsidered Harmful结论是不建议使用原因有二同一套参数强加给所有代码。--deep会把相同的 entitlements 和签名选项应用给它找到的每一段嵌套代码。App 和它内嵌的命令行工具往往需要不同的权限统一签名就是严重错误在 macOS 上甚至会导致可信执行系统直接拒跑只能签找得到的代码。它只在约定的嵌套代码位置找代码你把代码放在系统认为是数据的位置时--deep根本不会签它。正确姿势由内向外inside out逐个签名每段代码嵌套多就用脚本自动化。唯一例外是 Automator 应用。配套阅读Creating Distribution-Signed Code for Mac、Packaging Mac Software for Distribution。附赠一坑命令行工具双击被 Gatekeeper 拦截如果你的产品含命令行工具可能遇到Finder 双击被拦、Terminal 里运行却正常的现象。这是 macOS 已知缺陷r. 58097824Finder 双击走的是文档逻辑而非标准执行逻辑会无条件拦截。两种绕法✅ 把工具嵌入一个应用用户先运行应用并放行Gatekeeper 的判定会覆盖应用内的全部代码✅ 改用installer 包安装Gatekeeper 检查安装包后不再对安装内容做二次检查。排查工具箱三步定位签名问题第 1 步先分离签名问题与构建问题。Xcode 里跑得好好的发布版就崩是最常见的求助。原因是分发工作流同时改变了两个变量Release 构建配置 分发签名。隔离方法在 Xcode 归档器中用Development 签名重新分发——仍复现则是构建配置Release的问题把 Run 方案的构建设置改为 Release 即可在 Xcode 内复现调试不复现则是签名本身的问题。经验上绝大多数属于前者。第 2 步验证签名完整性。codesign -v -vvv --strict --deep是 Gatekeeper 调查的起手式配合codesign -d -vvv查看 cdhash 与 Authority。第 3 步读系统日志。日志中路径显示为private时先开启日志的私有数据记录见 Recording Private Data in the System Log。想理解签名底层机制cdhash、逐页哈希、CodeResources 封印资源读这篇签名机制科普会让你排查怪异问题时心中有数日志使用技巧参考 Your Friend the System Log。延伸阅读项目内资料索引 Code Signing Resources代码签名官方资源总索引 持续更新中 Resolving errSecInternalComponent errors during code signing证书报错系列问题的总入口️ Manual Code Signing Example手工签名完整示例 Signing a Mac Product For DistributionMac 产品分发签名 Resolving Hardened Runtime Incompatibilities强化运行时兼容问题 Isolating Code Signing Problems from Build Problems签名/构建问题隔离实操️ 完整目录见 README.md 的 Code Signing 与 Distribution 章节最后提醒本清单聚焦 Developer ID 签名代码——Gatekeeper 本不应拦截 App Store 应用若商店下载的 App 无法运行那是其他可信执行问题排查思路完全不同。【免费下载链接】The-Wisdom-of-QuinnShare and Enjoy®项目地址: https://gitcode.com/gh_mirrors/th/The-Wisdom-of-Quinn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考