快速获得Mac应用程序的管理特权 [英] Gain administration privileges with swift for a Mac Application

查看:153
本文介绍了快速获得Mac应用程序的管理特权的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一些需要经常以root特权运行命令的软件.

I am writing a pice of software that needs to often run a command with root privileges.

现在,我是通过向用户询问一次密码,然后保存密码,然后将该密码作为参数与with administrator privileges一起提供给NSAppleScript来实现的.

Right now, I am doing this by asking the user for their password once, saving it and then providing that password to NSAppleScript as an argument along with with administrator privileges.

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

This obviously is really insecure for the user as someone could gain access to their password.

我一直在寻找更好的一周时间,但是找不到解决方案.

I've been searching for a better part of a week and cannot find the solution.

SMJobBless seems to allow you to install your application with a higher privilege.

我遵循了应用程序的示例,并且从他们的SMJobBlessUtil脚本中收到错误消息.

I have followed app's example and I am getting an error from their SMJobBlessUtil script.

这是错误:

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)")

很明显,出了点问题.这是各自的支柱

Obviously, something is wrong. Here are the respective plists

服务信息列表

<?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>

应用信息列表

<?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>

我已经看过此stackoverflow帖子,还有许多其他人喜欢它.据我了解,我正确设置了塑料夹.我在做什么错了?

I've looked at this stackoverflow post and many others like it. As I understand them , I have my plists setup correctly. What am I doing wrong?

推荐答案

此方法的关键部分在ReadMe.txt的工作原理"下的属性列表"部分中进行了描述:

The key part of this approach is described under the "PROPERTY LISTS" section under "How It Works" of the ReadMe.txt:

[…]当您使用开发人员ID签署帮助工具时,Xcode会自动设置该工具的指定要求,这就是SMPrivilegedExecutables应该使用的要求.此外,这就是上面显示的"setreq"命令的作用:从构建的工具中提取指定的需求,并将其放入应用程序的Info.plist源代码中.

[…] 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.

由于您没有对产品进行签名(至少没有使用示例中描述的证书进行签名),所以此过程将始终失败.

Since you are not signing the products (at least, not with the certificate described in your examples), this process will always fail.

如果您不在开发人员计划中,则可以

If you are not in the Developer Program, you can create a self-signed certificate to sign with. However, this more or less defeats the purpose of the signing requirement. If you do not plan on enrolling in the Developer Program, you should be able to abbreviate the process as follows:

  1. 在应用程序的Info.plist中,将SMPrivilegedExecutables下的要求缩写为仅与助手的标识符匹配:

  1. In your app's Info.plist, abbreviate the requirement under SMPrivilegedExecutables to just match the helper's identifier:

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

  • 在助手的Info.plist中,将SMAuthorizedClients下的要求缩写为仅与应用程序的标识符匹配:
  • In your helper's Info.plist, abbreviate the requirement under SMAuthorizedClients to just match the app's identifier:

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

  • 忽略ReadMe.txt的构建和运行示例"说明,然后intead照常构建和运行项目.

我不能说我当然推荐这个;这些签名要求的存在是有充分理由的.但是,它至少比最终的替代方案要好,后者将使用NSAppleScript通过chmodchown为助手可执行文件提供根setuid位.

I can't say I recommend this of course; these signing requirements exist for good reason. It is at least better than the final alternative however, which would be using that NSAppleScript to give a helper executable a root setuid bit via chmod and chown.

附录在此处详细阐述了一些正在使用的概念:

运行特权代码会带来很多潜在的安全漏洞;安全地认证用户只是第一步.将所有特权操作委托给一个单独的进程是另一个重要的步骤,但是仍然存在的主要问题是如何确保您的应用程序(用户实际为其授予特权的应用程序)是唯一能够利用特权访问的实体.

Running privileged code comes with a lot of potential security holes; safely authenticating the user is only the first step. Delegating all privileged operations to a separate process is another strong step, but the major issue that remains is how to ensure that your app – the one the user actually granted privileges for - is the only entity capable of utilizing the privileged access.

Apple的示例演示了使用代码签名解决此问题的方法.以防万一,您不熟悉:代码签名涉及对最终产品进行加密标记,以使OS X可以验证您的程序没有被受感染的版本所取代.在原始示例的SMAuthorizedClientsSMPrivilegedExecutables中,那些额外的证书叶"引用是专门为此目的而设计的;它们描述了您的应用程序和帮助程序必须经过签名才能相互交互的证书.

Apple's example demonstrates the use of code signing to solve this problem. Just in case you're not familiar: Code signing involves marking your final products cryptographically in such a way that OS X can verify your programs haven't been replaced with compromised versions. Those extra "certificate leaf" references are in the original example's SMAuthorizedClients and SMPrivilegedExecutables are specifically for this; they describe the the certificate that your app and helper must have been signed with in order to interact with one another.

为帮助描绘图片,以下是其效果的粗略概述:

To help paint the picture a bit, here's a rough rundown of how this plays out:

  1. 您的用户授予启动以安装标记为com.domain.AppName.SampleService的帮助程序守护程序的权限.
  2. launchd在应用程序的Info.plist中的SMPrivilegedExecutables下找到com.domain.AppName.SampleService条目;它描述了辅​​助程序的二进制文件应与之签名的证书. (如果它们不匹配,那么从理论上讲,攻击者已用自己的版本替换了您的帮助程序工具,以便以root身份运行它.)
  3. 安装了有效的帮助程序工具后,您的应用会发出启动请求,以在您的控制下生成该帮助程序.此时,launchd会参考帮助程序工具的Info.plist的SMAuthorizedClients部分,以确保该应用程序确实有权运行该工具.而且,当然,它会验证您应用的签名,以确保它未被篡改.
  1. Your user grants authorization to launchd to install the helper daemon labeled com.domain.AppName.SampleService.
  2. launchd locates the com.domain.AppName.SampleService entry under SMPrivilegedExecutables in your app's Info.plist; this describes the certificate that the helper's binary should be signed with. (If they do not match, then theoretically an attacker has replaced your helper tool with their own version in order to run it as root.)
  3. With the valid helper tool installed, your app makes a request to launchd to spawn the helper under your control. At this point, launchd consults the SMAuthorizedClients section of your helper tool's Info.plist to ensure the app actually does have the right to run the tool. And, of course, it verifies your app's signature to ensure it hasn't been tampered with.

回到您的情况,您的产品当前的工作方式是消除签名步骤.您指示启动的唯一检查是您的应用程序的Info.plist是否将其ID列为"com.domain.AppName".由于也没有阻止攻击者更改其Info.plist的内容的方法,因此您可以寄希望于一旦他们控制了攻击者就无法使用您的帮助器工具造成任何伤害.

Getting back to your scenario, the way your products are currently working is by eliminating the signing steps. The only thing you have instructed launchd to check is whether your app's Info.plist lists its ID as "com.domain.AppName". Since there's nothing stopping an attacker from changing their Info.plist to say this as well, you're banking on the hope that they couldn't use your helper tool to do any harm once they have control of it.

概述其他选择的补充附录:

  • 正如我之前提到的,可以使用您在钥匙串访问"中创建的证书对代码进行签名.但是,由于该证书不会在授权机构(即Apple)处注册,因此像com.domain.AppName一样,进行欺骗也不会很困难.

  • As I alluded to previously, it is possible to sign your code using a certificate you created yourself in Keychain Access. However, since this certificate would not be registered with an authority (i.e. Apple), it wouldn't be any more difficult to spoof as com.domain.AppName would.

在您的应用程序和帮助程序之间的通信中,实施您自己的加密解决方案.例如,您可以

Implement your own cryptographic solution as part of the communication between your app and helper. As an example, you could could 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程序,以便按照Apple的意图对您的代码进行签名;这为您提供了OS X的其他好处,而不会通过身份不明的开发人员" schtick吓跑您的用户.

Enroll in the Apple Developer program in order to sign your code as intended by Apple; this gives you the additional benefit of OS X not scaring away your users with the "unidentified developer" schtick.

这篇关于快速获得Mac应用程序的管理特权的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆