2016-01-22 155 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代碼並不多。

相關問題