使用Intune审计macOS定位服务的技术指南

本文详细介绍如何使用Microsoft Intune和bash脚本审计macOS设备的定位服务访问,包含三个实用脚本实现定位图标显示控制、应用访问审计和报告生成,帮助企业平衡隐私保护与安全管理需求。

背景介绍

在加强macOS设备安全性的持续任务中,本文将重点关注macOS定位服务,以及CIS Level 2基准中的两项建议。我们将探讨建议2.6.1.2"确保’当系统服务请求您的位置时在控制中心显示位置图标’已启用"和建议2.6.1.3"审计定位服务访问"。

这两项CIS建议不仅能增强安全性,还能提高透明度,让用户和管理员能够清楚地了解谁在访问位置数据。

定位服务管理的重要性

探索这些设置让我理解了隐私与控制之间的平衡,并了解了如何利用Intune增强可见性和安全性。这不仅仅是关于这些设置是否对每个环境都是必要的,更多的是关于学习和个人发展。

建议2.6.1.2:通过位置图标确保可见性

当macOS系统服务或应用请求位置数据时,必须通过控制中心中的可见图标通知用户。这有助于建立信任,确保用户了解位置跟踪活动,防止任何隐藏进程被忽视。

建议2.6.1.3:审计定位服务访问

许多macOS功能依赖定位服务来提供定制信息,从设置时区和显示本地天气到启用"查找我的Mac"。虽然定位服务增加了便利性,但它们也可能带来隐私风险,特别是在政府或医疗保健等敏感环境中。

通过审计哪些应用可以访问定位服务,组织可以在可用性和数据安全之间保持平衡。

使用Intune部署脚本

为了简化定位服务设置的管理,我开发了三个可以通过Microsoft Intune部署的脚本。

1. 启用定位服务图标

首先,我们要确保当系统服务或应用请求您的位置时显示定位服务图标。

脚本概述:

  • 检查相关的plist文件(com.apple.locationmenu.plist)是否存在
  • 如果尚未激活,则启用"显示位置图标"设置
  • 记录所有操作以进行审计
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/bin/bash
#set -x
# -------------------------------------------------------------------------------------------------------------------------------
# Script to Ensure 'Show Location Icon in Control Center when System Services Request Your Location' Is Enabled
# CIS Benchmark Level 2 - 2.6.1.2 Ensure 'Show Location Icon in Control Center when System Services Request Your Location' Is Enabled
# -------------------------------------------------------------------------------------------------------------------------------

# Define variables
appname="EnableLocationIcon"
logandmetadir="/Library/Logs/Microsoft/IntuneScripts/$appname"
log="$logandmetadir/$appname.log"
plist_path="/Library/Preferences/com.apple.locationmenu.plist"

# Check if the log directory has been created
if [ -d "$logandmetadir" ]; then
    echo "$(date) | Log directory already exists - $logandmetadir"
else
    echo "$(date) | Creating log directory - $logandmetadir"
    mkdir -p $logandmetadir
fi

# Start logging
exec &> >(tee -a "$log")

# Begin Script Body
echo ""
echo "##############################################################"
echo "# $(date) | Starting running of script $appname"
echo "##############################################################"
echo ""

# Function to enable 'Show Location Icon for System Services'
function enable_location_icon {
    echo "$(date) | Checking if $plist_path exists."

    if [ -f "$plist_path" ]; then
        echo "$(date) | $plist_path exists. Checking current setting."
        current_setting=$(/usr/bin/defaults read "$plist_path" ShowSystemServices 2>/dev/null)

        if [[ "$current_setting" == "1" ]]; then
            echo "$(date) | 'Show Location Icon' is already enabled. No changes made."
        else
            echo "$(date) | 'Show Location Icon' is disabled or not set. Enabling now."
            /usr/bin/defaults write "$plist_path" ShowSystemServices -bool true
            chown root:wheel "$plist_path"
            chmod 644 "$plist_path"

            # Verify the change
            verify_setting=$(/usr/bin/defaults read "$plist_path" ShowSystemServices)
            if [[ "$verify_setting" == "1" ]]; then
                echo "$(date) | Successfully enabled 'Show Location Icon'."
            else
                echo "$(date) | Failed to enable 'Show Location Icon'. Please check manually."
            fi
        fi
    else
        echo "$(date) | $plist_path does not exist. Creating and enabling setting."
        /usr/bin/defaults write "$plist_path" ShowSystemServices -bool true
        chown root:wheel "$plist_path"
        chmod 644 "$plist_path"

        # Verify the change
        verify_setting=$(/usr/bin/defaults read "$plist_path" ShowSystemServices)
        if [[ "$verify_setting" == "1" ]]; then
            echo "$(date) | Successfully created $plist_path and enabled 'Show Location Icon'."
        else
            echo "$(date) | Failed to create $plist_path or enable 'Show Location Icon'. Please check manually."
        fi
    fi
}

# Execute the function
enable_location_icon

echo "$(date) | Script completed. 'Show Location Icon' setting has been applied."

2. 审计使用定位服务的应用

此脚本审计所有访问过定位服务的应用,并将它们编译成可读的plist文件。它就像我们脚本三人组中的侦探,为管理员提供了使用位置数据的应用的清晰概览。

脚本概述:

  • 将clients.plist从二进制转换为XML以便解析
  • 提取授权使用定位服务的应用的bundle ID
  • 将bundle ID解析为应用名称,并将其写入plist文件(com.company.locationapps.plist)
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
#!/bin/bash
#set -x
# -------------------------------------------------------------------------------------------------------------------------------

# Define variables
# Path to the Location Services database and temporary XML file
LS_DB="/var/db/locationd/clients.plist"
XML_DB="/tmp/clients.xml"
OUTPUT_FILE="/Library/Preferences/com.company.locationapps.plist"

# Step 1: Check if the Location Services database exists
if [ ! -f "$LS_DB" ]; then
    echo "Location Services Database not found at $LS_DB"
    exit 1
fi

# Step 2: Convert the binary plist to an XML format
# This is necessary because the original plist is in a binary format, which is not human-readable and cannot be easily parsed.
# Converting it to XML allows us to extract and manipulate the data more effectively.
plutil -convert xml1 -o "$XML_DB" "$LS_DB"

# Step 3: Initialize an empty array to store the names of authorized apps
authorized_apps=()

# Step 4: Filter out non-UTF-8 characters and parse authorized apps
while IFS= read -r bundle_id; do
    echo "Processing bundle ID: $bundle_id"
    app_path=$(mdfind "kMDItemCFBundleIdentifier == '$bundle_id'" | head -n 1)
    if [ -n "$app_path" ]; then
        app_name=$(mdls -name kMDItemDisplayName -raw "$app_path")
        if [ -z "$app_name" ]; then
            app_name=$(mdls -name kMDItemCFBundleName -raw "$app_path")
        fi
        if [ -z "$app_name" ]; then
            app_name=$(mdls -name kMDItemFSName -raw "$app_path")
        fi

        if [ -n "$app_name" ]; then
            echo "Found app: $app_name ($bundle_id)"
            authorized_apps+=("$app_name ($bundle_id)")
        else
            echo "Found app path but no display name for $bundle_id"
            authorized_apps+=("$bundle_id (No app display name found)")
        fi
    else
        echo "No app path found for $bundle_id"
        authorized_apps+=("$bundle_id (No app display name found)")
    fi

done < <(
    /usr/libexec/PlistBuddy -c "Print" "$XML_DB" | iconv -f UTF-8 -t UTF-8//IGNORE | 
    awk '
        BEGIN { authorized = 0; bundle_id = "" }
        /BundleId =/ { bundle_id = $3 }
        /Authorized = true/ {
            if (bundle_id != "") {
                print bundle_id
                bundle_id = ""
            } else {
                authorized = 1
            }
        }
        /^[^ ]/ {
            if (authorized && bundle_id != "") {
                print bundle_id
                authorized = 0
                bundle_id = ""
            }
        }
    '
)

# Step 5: Debugging - Check if the output file exists before creating a new one
# This step ensures we're aware if an existing plist file is already present. This can help in troubleshooting or verifying that the script is running as expected.
if ls -l "$OUTPUT_FILE"; then
    echo "DEBUG: File is visible to the script."
else
    echo "DEBUG: File is NOT visible to the script."
fi

# Step 6: Ensure the output file is freshly created on every run
# Removing the old plist ensures that no outdated or duplicate data remains. This guarantees that the plist only contains the most current information.
if [ -f "$OUTPUT_FILE" ]; then
    echo "Existing plist found. Removing it to create a fresh one."
    rm "$OUTPUT_FILE"
else
    echo "File Doesn't Exist, Will Create: $OUTPUT_FILE"
fi

# Step 7: Create a new plist with the required structure
# We initialize the plist with an 'AuthorizedApps' array to store the list of apps. This structure is required for consistent data formatting.
echo "Creating new plist file at $OUTPUT_FILE"
/usr/libexec/PlistBuddy -c "Add :AuthorizedApps array" "$OUTPUT_FILE"

# Step 8: Set permissions to ensure future detection and access
# Setting appropriate permissions ensures the file is readable and writable by system processes that may need to access or update it.
chmod 644 "$OUTPUT_FILE"
chown root:wheel "$OUTPUT_FILE"

# Confirm permissions to verify that they were set correctly
ls -l "$OUTPUT_FILE"

# Step 9: Populate the plist with the authorized apps
for app in "${authorized_apps[@]}"; do
    echo "Adding to plist: $app"
    /usr/libexec/PlistBuddy -c "Add :AuthorizedApps: string $app" "$OUTPUT_FILE"
done

# Step 10: Final confirmation message
echo "Location Services apps have been written to $OUTPUT_FILE"

3. 报告使用定位服务的应用

最后但同样重要的是,我们有了报告器。此自定义属性脚本设计用于Intune内的报告目的。它读取审计脚本生成的plist文件,并输出使用定位服务的应用列表。

脚本概述:

  • 从com.company.locationapps.plist读取
  • 将授权应用列表输出到控制台,以便在Intune中报告
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/bash
#set -x
# -------------------------------------------------------------------------------------------------------------------------------

# Define variables

OUTPUT_FILE="/Library/Preferences/com.company.locationapps.plist"

if [ -f "$OUTPUT_FILE" ]; then
    authorized_apps=$(defaults read "$OUTPUT_FILE" AuthorizedApps)
    echo "Authorized Apps: $authorized_apps"
else
    echo "No apps found using Location Services."
fi

隐私考虑

虽然审计定位服务访问对于维护安全至关重要,但承认潜在的隐私问题也很重要。列出所有访问位置数据的应用可能会无意中暴露有关用户如何与其设备交互的敏感信息。

潜在隐私风险:

  • 用户担忧:即使有最好的意图,用户也可能对管理员能够看到哪些应用访问其位置感到不安
  • 数据敏感性:在某些环境中,显示特定的应用名称可能会无意中披露敏感细节

缓解策略:

  • Intune设备面板中的可见性:值得注意的是,应用在Intune设备面板中已经可见
  • 匿名化数据:未来的脚本增强可以专注于匿名化这些数据。例如,我们可以在自定义属性中仅报告使用定位服务的应用数量,而不是列出实际的应用名称

未来脚本增强

脚本很好,但总有提升的空间。以下是一些将事情提升到新水平的想法:

  • 匿名报告:修改报告脚本,仅显示使用定位服务的应用数量,而不是它们的名称
  • 细粒度权限:引入逻辑来区分系统服务和第三方应用,提供更细致的报告
  • 自动警报:当新应用请求位置访问时通知管理员
  • 计划审计:自动化审计过程以定期运行,确保持续监控而无需管理开销
  • 维护批准的应用列表,仅对未知/未批准的应用发出警报

通过Microsoft Intune部署

分步部署指南:

  1. 将脚本上传到Intune:

    • 在Microsoft Intune中导航到设备 > macOS > 脚本
    • 分别添加前2个脚本,确保它们分配给适当的设备组
    • 导航到设备 > macOS > 自定义属性,上传报告脚本并将其也分配给设备
  2. 监控部署:

    • 使用Intune的报告功能验证脚本是否成功执行
    • 报告脚本将提供有关哪些应用正在访问定位服务的反馈
  3. 根据需要调整策略:

    • 根据审计结果,调整应用权限或告知用户潜在的隐私影响

结论

管理macOS上的定位服务不仅仅是关于锁定事物,而是关于在安全性和可用性之间取得平衡。通过定位服务图标显示谁在监视,审计跟踪应用行为,您可以完全控制而无需进行全面监视模式。

但请记住,能力越大,责任越大。牢记隐私,尽可能匿名化,并始终对用户保持透明。采用和沟通可以帮助有效应对这些挑战。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计