2016-01-22 154 views
5

我正在写一些需要经常以root权限运行命令的软件。用Mac应用程序获得swift的管理权限

现在,我通过询问用户密码一次,保存密码,然后提供密码NSAppleScript作为参数以及with administrator privileges

这对用户来说显然是不安全的,因为有人可以访问他们的密码。

我一直在寻找更好的一周的一部分,并找不到解决方案。

SMJobBless似乎允许您安装具有更高权限的应用程序。

我跟着应用程序的例子,我从他们的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

服务信息的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> 

应用信息的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和其他许多人喜欢它。据我了解,我的plists设置正确。我究竟做错了什么?

回答

6

这种方法的关键部分是“如何运作”的readme.txt的第下的“财产清单”中描述:

[…] when you sign the helper tool with a Developer ID, Xcode automatically sets the helper tool's designated requirement like this, and that's what you should use for SMPrivilegedExecutables. Moreover, this is what the "setreq" command shown above does: extracts the designated requirement from the built tool and put it into the app's Info.plist source code.

既然你不签的产品(至少不与你的例子中描述的证书),这个过程总是会失败。

如果你不在开发者计划中,你可以用create a self-signed certificate来签名。但是,这或多或少地破坏了签署要求的目的。如果您不打算注册开发人员计划,您应该能够按如下缩写过程:

  1. 在您应用的信息中,plist中,缩写SMPrivilegedExecutables下的要求只是比赛助手的标识:

    <string>identifier "com.domain.AppName.SampleService"</string>

    • 在你的助手的Info.plist,缩写SMAuthorizedClients下要求只匹配应用程序的标识:

    <string>identifier "com.domain.AppName"</string>

    • 忽略“构建并运行示例”ins ReadMe.txt的结构,intead只是简单地构建和运行项目。

我不能说我推荐,当然这一点;这些签署要求存在的理由很充分。然而,它至少比最终的替代方案更好,它将使用NSAppleScript通过chmodchown为助手可执行文件提供根setuid位。


附录阐述一些在这里打球的概念:

特权运行的代码与很多潜在的安全漏洞;安全地认证用户只是第一步。将所有特权操作委派给单独的进程是另一个强有力的步骤,但仍然存在的主要问题是如何确保您的应用程序 - 用户实际授予的权限 - 是唯一能够使用特权访问的实体。

Apple的示例演示了如何使用代码签名来解决此问题。以防万一您不熟悉:代码签名涉及以加密方式标记您的最终产品,以便OS X可以验证您的程序未被替换为受损版本。那些额外的“证书叶”参考在原始示例的SMAuthorizedClientsSMPrivilegedExecutables是专门为此;他们描述了您的应用程序和帮助程序必须签署的证书,以便彼此交互。

为了帮助绘制图画了一下,这里有一个如何发挥出一个粗略的纲要:

  1. 你的用户授予授权的launchd安装标记com.domain.AppName.SampleService助手守护进程。
  2. launchd在您应用的Info.plist中查找条目下的SMPrivilegedExecutables;这描述了助手的二进制文件应该签名的证书。 (如果它们不匹配,那么理论上攻击者已经用自己的版本替换了您的帮助工具,以便以root身份运行它。)
  3. 安装有效的帮助器工具后,您的应用程序发出请求launchd以产生帮助器在你的控制之下。此时,launchd会咨询您的帮助工具Info.plist的SMAuthorizedClients部分,以确保应用程序确实有权运行该工具。当然,它会验证你的应用程序的签名,以确保它没有被篡改。

回到您的方案,您的产品目前的工作方式是消除签署步骤。您已经指示launchd检查的唯一事情是您的应用的Info.plist是否将其ID标识为“com.domain.AppName”。由于没有什么能够阻止攻击者改变他们的Info.plist来说明这一点,所以你希望他们一旦控制了它,就不能使用你的帮助工具来造成任何伤害。

额外增编概述了替代方案:

+0

我不打算保持赏金。在Reddit上发布的问题是它说的是字符串。我确实是随机遇到了这个排列。但你的回答是够好的。我建议您编辑您的问题,以合并来自原始问题的逐步更改。我被困在这个好几天了,我仍然不明白这个不完整的身份线是如何的,而苹果有一个更长的字符串 – Cripto

+0

好吧,现在我不觉得这个傻瓜。再一次,奖励是没有必要的,但非常感谢......我已经更新了我的答案,试图解释你所问的关于整体的基本原理和具体情况;不要犹豫,如果没有涵盖它。 –

0

您正朝着正确的方向前进。目前特权辅助工具是在特权模式下执行任务的最佳实践。为了做到这一点,你也可以使用Swift,但只需用Swift替换C版本的函数调用即可。 (苹果公司已经推出了10.11 SDK的替代品)。例如,而不是

Boolean SMJobBless(CFStringRef domain, CFStringRef executableLabel, AuthorizationRef auth, CFErrorRef *outError); 

你可以使用:

SMJobBless(_: CFString!, _: CFString, _: AuthorizationRef, _: UnsafeMutablePointer<Unmanaged<CFError>?>) -> UInt8 

但我从来没有见过在互联网特权的辅助工具的例子。所以你需要看转换成Objective C代码。幸运的是Obj C代码并不多。

相关问题