简单来说,EDA通常指的是数据集的任何初始处理。通常,这些是较小的数据集,是较大数据集的子集,但你也可以使用大数据执行EDA。在本文中,你将扮演SecOps分析师的角色,对EDR( Endpoint Detection and Response:端点检测和响应)数据的快照执行EDA,这些数据可能来自主流工具。
测试数据
对于SecOps分析师来说,这可能需要处理原始数据集,如网络日志、历史端点检测与响应(EDR)事件、身份验证或通用身份与访问管理(IAM)日志,或几乎任何其他相关的安全或IT可观察性数据点。
在本文中,你将扮演SecOps分析师的角色,对EDR( Endpoint Detection and Response:端点检测和响应)数据的快照执行EDA,这些数据可能来自主流工具。该数据丰富且上下文丰富,其中包含有关发现、文件、设备、所有者、位置、操作系统信息和其他几个数据点的信息。
示例数据请在这里下载,总体来说,这个 JSON 数据结构非常全面且详细地记录了一次与端点检测和响应相关的事件信息,从事件本身的基础情况、涉及的设备、文件、进程到各种描述、时间、风险状态等多方面进行了呈现,多条这样的记录组成的数据集可用于安全分析、威胁追踪、系统监控等众多相关场景。
要执行此分析,您将使用Python脚本和DuckDB(一种可移植的进程内分析数据库)来学习如何为EDA编写基本的SQL语句。
快速开始
要将脚本中的每个块作为notebook运行,选择run Cell选项执行单元格代码。一个交互窗口将自动出现在VSCode中。
# %%
import duckdb
LOCAL_JSON = "../data/synthetic_edr_data_with_process.json"
# %%
duckdb.sql(
f"""
select count(*) from read_json('{
LOCAL_JSON}')
"""
).show()
# %%
查询结果:
┌──────────────┐
│ count_star() │
│ int64 │
├──────────────┤
│ 1000 │
└──────────────┘
如何返回数据量大,不利于我们查看分析,和所有事情一样,适度是关键。使用COUNT(*)是了解如何限制自己的一种信息丰富的方式,下面例子使用limit语句。LIMIT设置要从数据集检索的最大行数。作为一名人工分析师,使用LIMIT来减少EDA期间查看的数据量有助于防止在探索数据集时变得不堪重负。
# %%
duckdb.sql(
f"""
SELECT * FROM read_json('{
LOCAL_JSON}')
LIMIT 10
"""
).show()
返回结果:
┌─────────┬───────────┬───────────────┬───┬──────────────────────┬──────────────────────┬──────────────────────┐
│ action │ action_id │ activity_name │ … │ device │ file │ process │
│ varchar │ int64 │ varchar │ │ struct(uid_alt var… │ struct(accessed_ti… │ struct(created_tim… │
├─────────┼───────────┼───────────────┼───┼──────────────────────┼──────────────────────┼──────────────────────┤
│ Denied │ 2 │ Close │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
│ Denied │ 2 │ Update │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
│ Denied │ 2 │ Update │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
│ Denied │ 2 │ Close │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
│ Denied │ 2 │ Close │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
│ Denied │ 2 │ Update │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
│ Denied │ 2 │ Close │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
│ Denied │ 2 │ Close │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
│ Denied │ 2 │ Update │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
│ Denied │ 2 │ Close │ … │ {'uid_alt': sensor… │ {'accessed_time': … │ {'created_time': 2… │
├─────────┴───────────┴───────────────┴───┴──────────────────────┴──────────────────────┴──────────────────────┤
│ 10 rows 31 columns (6 shown) │
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
要强制行唯一性,请使用SELECT DISTINCT语句返回不同的(惟一的)值。在某些情况下,这有助于进一步减少返回的数据量,例如查询数据集中值得注意的唯一实例或指示符。例如,检索身份验证日志中用户的唯一名称,或者检索EDR数据集中设备的ip或uuid。
# %%
duckdb.sql(
f"""
SELECT DISTINCT * FROM read