网络活动日志记录

本文档介绍了设备政策控制器 (DPC) 如何记录网络活动。请继续阅读,了解如何向 DPC 添加网络日志记录。

概览

记录网络活动有助于企业检测和跟踪恶意软件在其设备上的传播。您的 DPC 可以调用网络日志记录 API,以报告来自系统网络调用的 TCP 连接和 DNS 查找。

通常,DPC 会将日志传送到服务器,以便向 IT 管理员显示。 您可能需要在服务器上或在设备本地进一步处理日志。例如,您可以设置 DNS 拒绝清单,以检测可疑行为并向 IT 管理员发出提醒。

可用性

Android 8 及更高版本支持设备所有者进行网络日志记录。如果启用,它会收集设备网络活动的相关数据。在 Android 12 及更高版本中,受管理个人资料的所有者和具有 DELEGATION_NETWORK_LOGGING 的受托应用也支持此功能。当配置文件所有者启用网络日志记录时,网络日志仅包含工作资料网络活动,不会从个人资料中收集数据。

我们建议您在 DPC 或设备用户创建新用户后,立即关联这些新用户。设备所有者可以监听广播或回调,例如 onUserAdded()(该回调会传递给设备所有者,而不是委托的日志记录应用),以便新用户的资料所有者可以关联该用户。如需了解详情,请参阅关联用户。

事件日志

启用网络日志记录后,Android 会记录使用系统网络库的应用中的每个事件。网络日志记录会记录两种类型的事件:

  • DNS 查找
  • 网络连接数

DNS 查找

网络日志记录会为属于系统网络请求一部分的 DNS 查找记录事件。日志会捕获将主机名解析为 IP 地址的每个 DNS 请求。其他支持性 DNS 查询(例如域名服务器发现)不会被记录。

网络活动日志记录 API 会将每个 DNS 查找呈现为 DnsEvent 实例。表 1 介绍了记录到 DnsEvent 中的字段和典型值。

表 1. DNS 事件字段

数据 示例 说明
主机名 host.example.com DNS 查询中发送的主机名。
Inet 地址 203.0.113.9、198.51.100.25 DNS 查询为主机名解析的 IPv4 或 IPv6 地址列表。为使日志大小可控,结果可能不会包含所有 IP 地址,请参阅下一行中的地址数量。
地址数量 4 DNS 查询解析返回的 IP 地址数量。您可以使用此功能来确定记录的 IP 地址是否是结果的子集。值为 0(零)表示主机名未解析为 IP 地址。
软件包名称 com.android.chrome 发出 DNS 查询的应用的软件包名称。
时间戳 1506297600000 记录 DNS 查找发生时间的时间戳。该值是 DNS 查找与世界协调时间 (UTC) 1970 年 1 月 1 日午夜之间的毫秒间隔。
ID 25 单调递增的数字 ID。适用于 Android 9.0(API 级别 28)或更高版本。

虽然 DNS 查找可以帮助 IT 管理员跟踪网络连接,但网络日志记录并不是通用的 DNS 记录解决方案。以下是应用可能会执行的一些未记录的 DNS 任务:

  • 直接与 DNS 域名服务器通信。
  • 调用 Java DNS 库以进行 DNS 查询。
  • 通过连接到固定 IP 地址来避免 DNS 查询。

网络连接数

网络日志记录会为属于系统网络请求的每次连接尝试记录一个事件。日志会捕获成功和失败的 TCP 连接,但不会记录 UDP 传输。

网络活动日志记录 API 将每个连接呈现为 ConnectEvent 实例。表 2 介绍了记录到 ConnectEvent 中的字段和典型值。

表 2. 连接事件字段

数据 示例 说明
Inet 地址 2001:db8::2f:abc:0 设备连接到的 IP 地址。这可能是 IPv4 或 IPv6 地址。
端口 80 设备连接到的 TCP 端口号。
软件包名称 com.android.chrome 已连接应用的软件包名称。
时间戳 1506297600000 记录网络连接发生时间的时间戳。该值是连接时间与世界协调时间 (UTC) 1970 年 1 月 1 日午夜之间的毫秒间隔。
ID 26 单调递增的数字 ID。适用于 Android 9.0(API 级别 28)或更高版本。

当应用调用标准网络库(例如 Android 的内置 API 或热门第三方库)连接到主机时,网络日志记录会记录一个事件。系统不会记录直接发出系统调用进行通信的应用。 请注意,系统不会记录 UDP 网络活动,因此某些媒体流式传输、即时通讯和游戏应用可能不会显示在日志中。

通知用户

系统会提醒设备用户,网络活动日志记录功能处于启用状态。用户会在界面中看到以下警告:

  • 设备管理对话框中的一个部分,说明您的 DPC 正在监控网络流量。用户在“快捷设置”中点按受管设备信息标签,即可看到该对话框。
  • 当用户刚开始使用网络日志记录功能时,系统会显示一条可关闭的系统通知。点按该通知会显示设备监控对话框,其中包含网络监控部分的进一步说明。当 DPC 停用网络日志记录时,通知会消失。

向 DPC 添加网络日志记录

为了帮助 IT 管理员查看网络日志,您的 DPC 需要能够完成以下任务:

  • 开启和关闭网络日志记录。
  • 在新批次准备就绪时检索所有记录的日志。
  • 将日志中的有用数据发送到服务器。

要求

Android 8.0(API 级别 26)或更高版本中的设备所有者以及 Android 12(API 级别 31)或更高版本中的受管理个人资料的个人资料所有者可以使用网络日志记录功能。在记录网络活动之前,DPC 应检查其是否为设备所有者或受管理个人资料的个人资料所有者。如果设备所有者启用了工作资料,则设备所有者中的网络日志不包含个人资料中的网络活动。

启用网络日志记录

如需开始记录网络活动,请调用 DevicePolicyManager 方法 setNetworkLoggingEnabled(),并将 true 作为 enabled 参数传递。您的 DPC 可以调用 isNetworkLoggingEnabled() 来检查是否记录了网络活动。

在 DPC 启用网络日志记录后,可能需要一段时间才能准备好第一批日志。您可能需要在界面中为 IT 管理员设置交付预期。

如需停止记录网络活动,请调用 setNetworkLoggingEnabled() 并传递 false。当 IT 管理员关闭网络日志记录功能时,系统会删除所有已收集但未报告的日志。

检索日志

DPC 可以批量检索日志,但网络日志记录 API 不提供对过去单个条目的随机访问。当有新一批日志可用时,DPC 的 DeviceAdminReceiver 子类会收到 onNetworkLogsAvailable() 回调。该回调包含一个批处理令牌,您的 DPC 可使用该令牌检索日志。您的 DPC 会调用 DevicePolicyManager 方法 retrieveNetworkLogs() 来获取网络事件列表。

以下示例展示了如何在 DeviceAdminReceiver 子类中检索日志:

Kotlin

fun onNetworkLogsAvailable(
        context: Context, intent: Intent, batchToken: Long, networkLogsCount: Int) {

    val dpm = getManager(context)
    var logs: List<NetworkEvent>? = null

    // Fetch the batch of logs with the batch token from the callback's arguments.
    try {
        logs = dpm.retrieveNetworkLogs(getWho(context), batchToken)
    } catch (e: SecurityException) {
        // Perhaps an unaffiliated user - handle the exception ...
    }

    // Process any logs ...
}

Java

public void onNetworkLogsAvailable(
    Context context, Intent intent, long batchToken, int networkLogsCount) {

  DevicePolicyManager dpm = getManager(context);
  List<NetworkEvent> logs = null;

  // Fetch the next batch of logs using the callback's batch token argument.
  try {
    logs = dpm.retrieveNetworkLogs(getWho(context), batchToken);
  } catch (SecurityException e) {
    // Perhaps an unaffiliated user - handle the exception ...
  }

  // Process any logs ...
}

您的 DPC 应立即检索日志,因为系统会删除日志,以便为新批次腾出空间。您可能需要保留日志的本地副本,直到您确定 DPC 已顺利处理所有日志。

处理任何日志

一批日志通常包含 DnsEvent 和 ConnectEvent 实例的混合。如需详细了解 DNS 查找和网络连接的数据字段,请参阅事件日志。事件按时间顺序排列,每个批次包含不超过 1,200 个事件。

调用检索日志的方法后,请检查返回值是否不为 null。如果发生以下任一情况,该值可能为 null:

  • 批次令牌所代表的批次已不再可用。您的 DPC 无法检索该批次,应等待下一批次。
  • IT 管理员已停用网络日志记录。

以下简化示例展示了 DPC 如何提取解析的 DNS 主机名。您的 DPC 需要更复杂的处理和报告。

Kotlin

// Here, logs might be null. We can't fix because either the token doesn't match
// the current batch or network logging was deactivated.
// Confirm with isNetworkLoggingEnabled().

logs?.forEach {
    // For this example, report the DNS hosts and discard all other data.
    // Because we use the event ID, this example requires API level 28.
    if (it is DnsEvent) {
        reportDnsHostToServer(it.hostname, it.getTimestamp(), it.getId())
    }
}

Java

if (logs == null) {
  // Abandon processing because either the token doesn't match the current batch
  // or network logging was deactivated - confirm with isNetworkLoggingEnabled().
  return;
}

for (NetworkEvent event : logs) {
  // For this example, report the DNS hosts and discard all other data.
  // This example requires API level 28 because we use the event ID.
  if (event instanceof DnsEvent) {
    reportDnsHostToServer(
        ((DnsEvent) event).getHostname(), event.getTimestamp(), event.getId());
  }
}

上面的示例还展示了如何获取 Android 9.0(API 级别 28)或更高版本中包含的事件的数字 ID。由于每个事件的 ID 都会单调递增,因此您可以帮助 IT 管理员发现日志中的缺口。每当 DPC 启用日志记录或设备重启时,系统都会重置该 ID。

您的 DPC 可以将整个集合发送到服务器,您也可以决定在设备上过滤事件。例如,您可能只报告已添加到 IT 管理员许可清单中的事件。

开发和测试

在开发和测试期间,您可能希望接收 onNetworkLogsAvailable() 回调,而无需浏览数百个网页。在 Android 9.0(API 级别 28)或更高版本中,您可以发出一些示例网络请求,并强制系统发送日志可用回调。在终端中运行以下 Android 调试桥 (adb) 命令:

adb shell dpm force-network-logs

系统会限制您使用该工具的频率,并在终端输出中报告任何有意减慢的情况。如果没有要检索的日志,您的 DPC 将不会收到回调。