我正在写一些需要经常以root权限运行命令的软件。
现在,我这样做是通过向用户询问他们的密码一次,保存密码,然后将该密码作为参数提供给NSAppleScript
以及with administrator privileges
。
这显然对用户来说是不安全的,因为有人可以访问他们的密码。
我一直在寻找更好的一周时间,但找不到解决方案。
SMJobBless似乎允许您以更高的权限安装您的应用程序。
我已经关注了app的示例,我从他们的SMJobBlessUtil脚本中收到错误。
这是错误:
SMJobBlessUtil.py: tool designated requirement (identifier "com.domain.AppName.SampleService" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: firstName lastName (XXXXXXXXXX)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */) doesn't match entry in 'SMPrivilegedExecutables' (anchor apple generic and identifier "com.domain.AppName.SampleService" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.CN] = "Mac Developer: firstName lastName (XXXXXXXXXX)")
显然,出了点问题。以下是相应的帖子
服务信息plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>com.domain.AppName.SampleService</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>SampleService</string>
<key>CFBundleVersion</key>
<string>6</string>
<key>SMAuthorizedClients</key>
<array>
<string>anchor apple generic and identifier "com.domain.AppName" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = xxxxxxxxxx)</string>
</array>
</dict>
</plist>
Apps Info plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<dict/>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleGetInfoString</key>
<dict/>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Away</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.99</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>9</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>LSUIElement</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 firstName lastName. All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>SMPrivilegedExecutables</key>
<dict>
<key>com.domain.AppName.SampleService</key>
<string>anchor apple generic and identifier "com.domain.AppName.SampleService" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.CN] = "Mac Developer: firstName lastName (XXXXXXXXXX)"</string>
</dict>
</dict>
</plist>
我看过at this stackoverflow post和其他很多人喜欢它。据我所知,我的钳子设置正确。我做错了什么?
答案 0 :(得分:6)
此方法的关键部分在ReadMe.txt的“工作原理”下的“财产列表”部分中描述:
[...]当您使用开发者ID对帮助工具进行签名时,Xcode会自动设置帮助工具的指定要求,这就是您应该为SMPrivilegedExecutables使用的内容。此外,这就是上面显示的“setreq”命令:从构建的工具中提取指定的需求并将其放入应用程序的Info.plist源代码中。
由于您未签署产品(至少不使用示例中描述的证书),此过程将始终失败。
如果您不在开发者计划中,可以create a self-signed certificate进行签名。然而,这或多或少地违背了签署要求的目的。如果您不打算注册开发人员计划,您应该能够按如下方式缩短该流程:
在您的应用的Info.plist中,缩写SMPrivilegedExecutables
下的要求以匹配帮助者的标识符:
<string>identifier "com.domain.AppName.SampleService"</string>
SMAuthorizedClients
下的要求缩写为仅匹配应用的标识符: <string>identifier "com.domain.AppName"</string>
我不能说我当然推荐这个;这些签署要求存在是有充分理由的。它至少比最终替代方案更好,然而,它将使用NSAppleScript通过chmod
和chown
向帮助程序执行根setuid位。
附录详细阐述了这里的一些概念:
运行特权代码会带来许多潜在的安全漏洞;安全地验证用户只是第一步。将所有特权操作委派给单独的进程是另一个重要步骤,但仍然存在的主要问题是如何确保您的应用程序 - 用户实际授予的权限 - 是唯一能够利用特权访问权限的实体。
Apple的示例演示了使用代码签名来解决此问题。以防您不熟悉:代码签名涉及以加密方式标记您的最终产品,以便OS X可以验证您的程序是否未被受损版本替换。那些额外的“证书叶子”引用在原始示例SMAuthorizedClients
中,SMPrivilegedExecutables
专门用于此;他们描述了您的应用和帮助者必须签署的证书,以便彼此互动。
为了帮助描绘一下图片,这里有一个粗略的概述:
com.domain.AppName.SampleService
的帮助程序守护程序。com.domain.AppName.SampleService
下的SMPrivilegedExecutables
条目;这描述了应该使用帮助程序的二进制文件签署的证书。 (如果它们不匹配,那么理论上攻击者已经用自己的版本替换了你的帮助工具,以便以root身份运行它。)SMAuthorizedClients
部分,以确保应用程序确实有权运行该工具。当然,它会验证您应用的签名,以确保它没有被篡改。回到您的方案,您的产品目前的工作方式是取消签名步骤。你指示启动检查的唯一一件事是你的应用程序的Info.plist是否将其ID列为“com.domain.AppName”。由于没有什么可以阻止攻击者更改他们的Info.plist来说明这一点,所以你希望他们一旦掌握了它就无法使用你的助手工具做任何伤害。
其他附录概述了替代方案:
正如我之前提到的,可以使用您自己在Keychain Access中创建的证书对代码进行签名。但是,由于这个证书不会在权威机构(即Apple)注册,因此com.domain.AppName
的欺骗行为也不会更难。
实施您自己的加密解决方案,作为您的应用和帮助之间通信的一部分。例如,你可以generate a pair of keys during installation of the helper, store them via Keychain Services so that your programs have access to them, and verify them against one another when using the helper in the future.
注册Apple Developer program,以便按照Apple的意图签署您的代码;这为您提供了OS X的额外好处,而不是通过“身份不明的开发人员”schtick吓跑您的用户。
答案 1 :(得分:0)
你正朝着正确的方向前进。当前特权帮助工具是在特权模式下执行任务的最佳实践。为此,您也可以使用Swift,但只需用Swift替换C版函数调用。 (Apple在10.11 SDK中引入了替代品)例如,而不是
Boolean SMJobBless( CFStringRef domain, CFStringRef executableLabel, AuthorizationRef auth, CFErrorRef *outError);
你可以使用:
SMJobBless(_: CFString!, _: CFString, _: AuthorizationRef, _: UnsafeMutablePointer<Unmanaged<CFError>?>) -> UInt8
但我从未见过Internet中特权助手工具的例子......所以你需要看看Objective C代码。幸运的是Obj C代码并不多。