第2章 数据资产盘点:如何发现企业内的结构化/非结构化数据源、元数据收集方法

2.1 盘点前的灵魂拷问

在做DSPM扫描之前,你得先搞清楚一个问题:你的数据到底散落在哪儿?

我见过不少团队,一上来就拿着扫描工具到处扫,结果扫出一堆临时文件、缓存日志,真正的敏感数据反而没抓到。说白了,没做资产盘点就直接扫描,就像蒙着眼进迷宫。

所以我习惯把资产盘点分成三个层次:数据源发现 → 元数据采集 → 资产目录建立。这章我们就聊前两步——怎么把藏在各个角落的数据源挖出来,再把它们的“身份证”(元数据)收集上来。

核心观点:资产盘点不是为了扫而扫,而是为了给后续的分类分级打地基。地基不稳,后面全白干。

数据资产盘点三层模型 数据资产盘点三层模型 数据源发现 扫描网络、文件系统、数据库、云存储、SaaS应用 元数据采集 技术元数据 + 业务元数据 + 管理元数据 资产目录建立 统一编目、去重、血缘追踪、标签化

2.2 结构化数据源:数据库与数据仓库

先从最熟悉的开始说。结构化数据,说白了就是关系型数据库里的表——MySQL、PostgreSQL、Oracle、SQL Server这类。它们的特点是schema明确,字段类型固定,元数据好拿。

发现方法:我记得第一次帮客户做盘点,他们自己都不知道内部有38套数据库实例。后来我写了个轻量脚本,直接连CMDB或者用nmap扫常见端口(3306、5432、1521等),再配合云厂商的RDS列表API,基本能覆盖90%。

小技巧:别光依赖人工运维清单。翻翻公司的内部Wiki、OnCall文档、甚至Git仓库里的docker-compose.yml,往往能发现被遗忘的开发库或测试库。

元数据采集清单:对每个数据库实例,至少得收这些:

  • 数据库名称、版本、字符集
  • 所有库、所有表、所有字段名与数据类型
  • 主键、外键、索引、视图、存储过程
  • 表行数(近似值)与存储大小
  • 最近DDL/DML时间戳

为什么收这些?因为后面的数据分类分级,很大程度上依赖字段级别的元数据。比如字段名叫“id_card”,那大概率是身份证号,得重点关注。

2.3 非结构化数据源:文件系统与云存储

非结构化数据才是真正的老大难。一个企业里,结构化数据可能只占20%,剩下80%是文件——Word、PDF、Excel、图片、日志、源代码……它们散落在文件服务器、NAS、S3桶、SharePoint、Confluence等各个角落。

我之前遇到过一个客户,光S3桶就开了200多个,有些桶权限配得特别松,连外包商都能读。我们写了个Python脚本,用boto3遍历所有桶的列表和对象元数据,才把数据源摸清楚。

非结构化数据源的分类:

类型 常见载体 文件格式举例
办公文档 文件服务器、SharePoint、Google Drive .docx, .pdf, .xlsx, .pptx
多媒体文件 NAS、OSS、S3 .jpg, .mp4, .wav
日志与导出 ELK、Splunk、HDFS .log, .csv, .json
源代码与配置 GitLab、GitHub、内部仓库 .py, .java, .yaml, .conf
备份与归档 Tape、冷存储、Glacier .tar, .gz, .bak

元数据怎么收?对于文件系统,核心元数据包括:

  • 文件路径、文件名、扩展名
  • 创建时间、最后修改时间、最后访问时间
  • 文件大小、权限(owner、group、ACL)
  • 文件类型(通过magic bytes识别,不只看后缀)
  • 是否加密、是否压缩

注意坑:我曾经踩过一个雷——只靠文件后缀判断类型,结果有人把敏感数据表重命名为.jpg藏在图片文件夹里。后来改用file命令读取魔数,才真正识别出来。所以,永远不要轻信后缀名。

2.4 半结构化数据源:NoSQL与日志流

半结构化数据介于两者之间——有结构但schema灵活。典型代表:MongoDB、Elasticsearch、Redis、Kafka Topic里的JSON消息。

嗯,这里要特别提一下NoSQL数据库。它们的元数据不像关系型那么规整。MongoDB你得通过listDatabases、getCollectionInfos接口拿集合名和文档样例;Elasticsearch得调_cat/indices和_mapping。收的时候注意别把整个文档全拉下来,那样数据量太大,只取字段路径和类型就行了。

# MongoDB元数据采集示例(Python)
from pymongo import MongoClient

client = MongoClient("mongodb://admin:password@localhost:27017")
dbs = client.list_database_names()
for db_name in dbs:
    db = client[db_name]
    colls = db.list_collection_names()
    for coll_name in colls:
        sample = db[coll_name].find_one()  # 取一条样本
        if sample:
            fields = list(sample.keys())
            print(f"{db_name}.{coll_name}: {fields}")

2.5 元数据收集的三种模式

在实际干活的时候,元数据收集不能靠人工一个一个点,得讲方法。我一般用三种模式:

  1. 直连扫描:直接连数据库、文件系统、云API。实时性强,适合新环境首次全量盘点。
  2. 日志采集:从审计日志、访问日志、查询日志中提取数据源信息。适合已经跑起来的业务,不影响生产。
  3. 代理部署:在目标服务器上装轻量Agent,定期上报元数据。适合大规模、跨机房的环境。

每种模式各有优劣,我画了张表对比:

模式 实时性 侵入性 覆盖范围 适用场景
直连扫描 高 中(需授权) 广 首次盘点、小规模环境
日志采集 中 低 中 生产环境、持续监控
代理部署 高 高 广 大规模、多数据中心

我的经验:别上来就上代理。先直连扫一轮摸清家底,再决定是否持续用日志或代理。否则代理人多了,运维那边的告警会把你淹死。

2.6 常见避坑与最佳实践

干这行几年,踩过的坑我可以列一个list:

  • 权限不足扫不全——我曾经因为只用了只读账号,漏掉了好几个关键数据库。后来我要求在盘点阶段向安全团队申请一个“准管理员”角色,扫描完立刻回收。
  • 忽略影子IT——员工自己搭的MySQL、内部用的SaaS(如飞书、钉钉文档)、部门级的NAS,这些都不在IT资产管理范围内。我建议在盘点邮件里加一句“如果团队有自己的存储,请通报”,配合问卷调查。
  • 元数据过度采集——有些人恨不得把每行数据都拉回来。其实没必要,收集字段级元数据就够了,内容级的扫描放到后续的数据分类分级环节去做。
  • 不记录时间戳——元数据会变,如果你不记录采集时间,后面根本没法做增量更新。我每个条目都会加一个collect_ts字段。

2.7 本章小记