本文档解释了设备策略控制器 (DPC) 如何记录网络活动。继续阅读以了解如何向您的 DPC 添加网络日志记录。
概述
记录网络活动可以帮助企业检测和跟踪其设备上恶意软件的传播。您的 DPC 可以调用网络日志记录 API 来报告来自系统网络调用的 TCP 连接和 DNS 查询。
通常,您的 DPC 会将日志发送到服务器以供 IT 管理员查看。您可能希望在服务器上或设备本地进一步处理日志。例如,您可以设置 DNS 黑名单以检测可疑行为并向 IT 管理员发出警报。
可用性
Android 8 及更高版本中支持设备所有者的网络日志记录。如果启用,它将收集设备网络活动的数据。Android 12 及更高版本也支持托管配置文件的配置文件所有者和具有 DELEGATION_NETWORK_LOGGING 的委派应用。当配置文件所有者启用网络日志记录时,网络日志仅包含工作配置文件网络活动,不会收集个人配置文件的数据。
要了解更多信息,请阅读 关联用户。
事件日志
当网络日志记录处于活动状态时,Android 会记录使用系统网络库的应用的每个事件。网络日志记录记录两种类型的事件
- DNS 查询
- 网络连接
DNS 查询
网络日志记录会为作为系统网络请求一部分的 DNS 查询记录一个事件。日志会捕获将主机名解析为 IP 地址的每个 DNS 请求。其他辅助 DNS 查询(例如名称服务器发现)不会被记录。
网络活动日志记录 API 将每个 DNS 查询显示为 DnsEvent
实例。表 1 描述了记录到 DnsEvent
中的字段和典型值。
数据 | 示例 | 描述 |
---|---|---|
主机名 | 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 查询发生时间的 timestamps。该值是 DNS 查询与 1970 年 1 月 1 日午夜(UTC)之间的毫秒间隔。 |
ID | 25 | 单调递增的数字 ID。在 Android 9.0(API 级别 28)或更高版本中可用。 |
虽然DNS查找可以帮助IT管理员跟踪网络连接,但网络日志记录并非通用的DNS记录解决方案。以下是一些应用可能执行但不会记录在日志中的DNS任务。
- 直接与DNS名称服务器通信。
- 调用Java DNS库进行DNS查询。
- 通过连接到固定IP地址来避免DNS查询。
网络连接
网络日志记录系统网络请求中每次尝试连接的事件。日志捕获成功和失败的TCP连接——UDP传输不会被记录。
网络活动日志记录API将每个连接表示为ConnectEvent
实例。表2描述了记录到ConnectEvent
中的字段和典型值。
数据 | 示例 | 描述 |
---|---|---|
Inet 地址 | 2001:db8::2f:abc:0 | 设备连接到的IP地址。这可能是IPv4或IPv6地址。 |
端口 | 80 | 设备连接到的TCP端口号。 |
包名 | com.android.chrome | 连接应用的包名。 |
时间戳 | 1506297600000 | 记录网络连接时间的Timestamp。值为连接时间与1970年1月1日午夜UTC之间的毫秒间隔。 |
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查找和网络连接的数据字段的更多信息,请参见事件日志。事件按时间顺序排列,每个批次最多包含1200个事件。
调用检索日志后,请检查返回值是否不为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将不会收到回调。