本文作者:mcvoodoo

如何基于内容进行数据分类,在数据安全领域一直是个很大的挑战。传统上通过类DLP系统监控终端来实现数据指纹识别,但在大规模互联网公司里数据不断变化,这种方法扩展性很差,同时在发现数据位置时效率也很低下。

基于这些问题,我们设计了一个端到端系统用于进行敏感语义自动识别的系统,结合了机器学习和传统指纹技术对所有数据进行分类,在生产中几十个存储类型投入使用,F2-Score平均0.9(查准率和查全率的加权调和平均数,基于全面识别的重要性,本指标更侧重于查全率)。

简介

在公司内,数据以多种格式和位置大量分布存储,数据会在很多地方复制缓存多次,结果就是敏感数据信息大量分散,在满足监管合规等要求时就会面临极大的困境。例如合规要求必须对所有银行卡号进行脱敏,那第一步就是找到系统内所有的银行卡号,这个时候数据分类就成为了关键能力。通过数据分类系统,自动找到所有相关数据,再进一步进行各类控制措施。

数据发现和分类需要快速、有效寻找和标记数据。但在大多数企业内,这个工作人工成分较大,通常流程是:

1、根据法规确定敏感信息类型级别,然后据此建立分类策略。

2、类DLP系统进行指纹识别,对下游端点监控。

这算是做得好的情况,还能做一些指纹识别工作。这种处理方式在一个大规模企业中PB级数据时,不具备扩展性。

所以我们的需求是建一个数据分类系统,可扩展到持久性和非持久性数据,对数据类型和格式无限制。这是个很大挑战,包括以下问题:

有些数据可能包含几千个字符,所以需要使用一组有效特征来表示,这些特征可较为容易的聚合和移动。

特征不仅要能准确分类,还需要灵活可扩展,以便将来增加新的数据检测类型。

我们还需要处理大型离线表,持久性数据会被存储在很多PB大小的表中,会导致扫描速度极慢,因此需要较高的性能。

2 系统架构

为了应对大规模的持久数据和实时数据挑战,数据分类系统分为两个独立的流程。

2.1 持久数据

首先系统要能理解数据的宇宙,因此对每个存储收集了基本信息,包括数据中心、对应系统及资产,这就形成了一个元数据目录,使系统能够有效检索数据而不至于数据过载。元数据目录为所有资产扫描提供了一个可信来源,能够跟踪不同资产的状态,再根据这些信息确定优先级。从系统中可获取的信息包括最后一次扫描时间、资产最近的创建时间以及历史信息,以及该资产过去占用的内存和CPU。最后对于每一个数据资产在资源可用时,调用作业执行实际扫描。

每个扫描作业都是一个编译的二进制文件,对最新数据进行伯努利采样。资产被分解为列,每列的分类结果均单独处理。另外系统会扫描列内任何负数据,包括json、数组、编码结构、URL、base 64序列化数据等,这些会显著增加扫描时间,例如在一个json blob里,一个表可能有上万的嵌套列。

对于数据资产中被采样的每一行,分类系统从内容中提取浮点和文本特征,并将特征关联到所取的列。因此,特征提取步骤的输出是每一列的所有特征map。

2.1.1 特征

特征的概念对系统来说是一个关键要素,与其说是浮动和文本特征,不如说可以通过每个数据资产中直接获取的原始字符串样本。此外机器学习模型可以直接在每个样本上进行训练,而不是近似样本的特征数。

这里几个关键原因:

1、隐私优先:特征只在内存中存储获取的样本,对非持久化数据来说更为重要,因为服务需要在预测之前保持一些分类状态。

2、记忆能力:有些样本可能有几千字符长度,如果存储并传递的话,会增加很多不必要的开销,再随着资产的增加,最后系统难以持续。

3、聚合特征:特征可以快速表示扫描结果,系统方便合并之前的扫描结果,这对多次运行的扫描任务汇总有分析帮助。

然后特征发送到预测服务,预测服务采用基于规则分类和机器学习预测每列数据标签,从中选择最优预测。

规则分类器是人工启发式的,用计数和比率对0到100的范围进行特征归一化。一旦生成了初始分数,且数据相关的列名不属于任何 "拒绝列表",规则分类器就会在所有数据类型中挑选出最高的归一化分数。

由于分类的复杂性,完全使用人工启发式方法会导致分类结果不理想,尤其是对于非结构化数据。所以还需要机器学习系统来处理非结构化数据的分类,例如用户生成的评论,地址等。使用机器学习可以利用更多的数据信号如列名、数据血缘等,可大大提高精度。

预测服务存储每列的结果,以及有关扫描时间和状态的元数据。任何依赖于这些数据的消费和下游流程都可从每日发布的数据集中读取,所以也提供了实时API。

2.2 非持久数据

非持久化的流量也是敏感数据的一部分,因此系统也提供了在线API,用于为非持久化流量生成实时分类预测。实时预测系统适用于出口流量、机器学习模型流量、流经系统的各类客户数据。

API需要两个主要参数:分组密钥和原始数据。服务执行特征提取,并对同一key特征进行分组。特征维护在持久化缓存中,用于故障恢复。对于每个分组密钥,服务确保具备足够的样本,然后遵循上述相同过程。

2.3 优化

对存储的扫描使用Library以优化读取,并能确保并发访问的干扰。真正的难点是大表(50+PB)扫描,内存效率再优化都难以支撑,系统很难在内存耗尽之前完成扫描计算,毕竟扫描是在内存中,也无法长时间内持久化。如果表中有几千列包含非结构化的blob型,在对整表预测时肯定会失败。为解决这个问题,使用了proxy作为负载代理,能够预测内存问题,且可用更少的数据预先计算特征。

2.4 数据

一个数据分类系统的好坏,取决于所提供的数据本身,可分为几类:

基于内容:当然最重要的就是内容。对内容进行进行伯努利采样,并在数据本身的内容上运行特征提取。系统中的许多特征都是从内容中提取出来的。例如浮动特征,这些特征代表某类型的样本被看到的次数计数。实际上可能是在抽样中看到的电子邮件数量,或表情符号数量,这些特征可以标准化并汇总。

数据血缘:血缘可以了解内容的变化。例如哈希数据,当对子表中的数据进行哈希时,则说明哈希数据来自一个父表,其中的数据可能是明文。当数据不清晰可读、上游转换过来时,血缘则可以辅助决策。

注释:注释也可帮我们识别非结构化数据,注释和血缘数据结合,在不同的数据资产中传播属性。注释可帮助识别非结构化数据的源头,而血缘数据可帮助追踪数据的流向。

数据注入:数据注入是将特殊不可读字符注入到已知数据类型中,当扫描到相同内容时,即可判断为来自已知类型。

2.5 衡量指标

分类系统需要一个严格的衡量指标的方法,迭代改进的主要指标是精度和召回率,对每个标签以F2得分作为系统的核心指标。为客观观察指标,需要一个独立的方法来衡量,而不是依靠系统本身。

2.5.1 数据标注

通过以下方法数据标注集,以迭代改进指标:

日志框架配置:Hive表中的某些字段会被填入已知的数据类型,这些数据可以作为可靠事实。

手动标注:数仓中有些人工标注标签,是非结构化数据的可靠来源。

血缘传播:来自父表列的标记和注释或注释,可在下游表中跟踪这些数据。

抽样代码路径:内部代码路径会携带某种类型数据,扫描器可对这些具有已知数据类型的代码路径进行采样。

采样表:对整个数据集的大型Hive表随机抽样扫描。

合成数据:对一些简单类型的公共数据进行自动生成,例如GPS、位置类数据。

将这些数据源组合成一个语料库,目的是为了尽量确保他们能够代表数仓,否则分类引擎会过度适应。因此训练时用上以上所有资源来确保模型指标,同时人工标注进行抽样打标,保持数据收集不会跑偏。

2.5.2 持续集成

为了实现快速迭代改进,需要实时衡量系统性能,从而进一步以数据为导向,以战术为依据。这部分介绍系统完成数据标注提供的反馈循环。

调度系统识别到数据资产后,调度两个作业:一个作业使用生产扫描器,因此是生产特征;另一个候选版本(RC)作业使用新构建的扫描器,因此是最新的RC特征。每个扫描器将作业输出写到一个表内,将版本与分类结果一起标记。

这么做的用处是可以将RC和生产结果实时比较,并有明确方法衡量改进。当比较RC和PROD特征时,同时还记录预测服务的ML分类引擎的变化:最近建立的机器学习模型,当前生产中的模型,以及测试前改进的模型。这样可针对不同的模型版本进行 "切割",并实时比较指标。可快速确定一个机器学习模型实验何时可以推广到生产中。

每晚计算出的RC特征被发送到ML模型训练流水线,ML模型根据最新的RC特征进行训练,并根据真实数据集评估性能。

每天早上ML模型完成训练后,自动将模型作为实验模型发布并自动纳入实验模型列表。

2.5.3 实际指标情况

系统对100多种不同的数据类型进行了高精度的标注。结构良好的数据类型如电子邮件和手机号码,分类的f2分数超过0.95。内容自由的数据类型如用户评论和姓名,表现也非常好,f2-score超过0.85。

系统每天都对所有数据存储中的持久化数据和在线数据的大量单个列进行分类,可在10多个数据存储中扫描超过500TB的数据,其中大部分数据存储的覆盖率超过98。

随着时间的推移,系统的效率变得更高,分类作业从扫描资产到计算每个列的预测,平均35秒完成。下图是RC特征发送到ML模型的集成流程图。

3 机器学习系统组件

在几百种数据类型和非结构化的内容的情况下,使用人工启发式分类法会导致分类精度不高,尤其是对于非结构化数据。基于这个原因需要机器学习系统来处理复杂性质的非结构化数据摆脱人工启发式方法,并利用特征和额外数据(列名、血缘等)以提高检测精度。

模型分别在密集和稀疏特征上学习嵌入,然后将其连接起来形成一个向量,通过一系列的批量归一化阶段和非线性最终输出。最终输出是每个标签在[0-1]之间的一个浮点数,表示给定示例属于给定敏感度类型的概率,利用 PyTorch (Python的机器学习库)来建模更快。

在架构设计过程中,由于稀疏(如基于文本)和密集(如数字)特征的内在差异,需要分别建模。对于最终的架构,做参数扫描也很重要,以便找到学习率、批次大小和其他模型超参数的最佳值。优化器的选择也是一个重要的超参数,比较流行的Adam算法往往会导致模型过拟合,而SGD算法往往会产生一个更稳定的模型(SGD参数稳定性更好)。还有一些额外的细微差别,必须直接纳入模型,比如静态规则,它确保当给定特征具有特定值时,模型输出确定性的预测。这些静态规则由用户指定,可产生一个自给自足的可靠架构。另外要注意的是,在训练过程中,这些规则需要关闭,以免影响到梯度下降训练过程。

3.1 难点

难点一是标注数据质量。模型需要每个类别的高质量数据才能学习特征和标签之间的关联。通过对这些数据的分析发现,像信用卡号和银行账号这样的数据类在我们的仓库中并不是非常普遍(被加密和脱敏),因此很难收集大量真实数据来训练。为了解决这个问题,我们开发了为这类生成合成值的工具。这种生成工具还有个好处是处理的不是真正隐私数据,避免了安全风险。

难点二是开放架构挑战,比如隔离变化和提前停止。隔离变化是指当网络的发生各种变化时,影响会被隔离到特定的类,而不会对整个预测性能产生大范围影响。提前停止可在所有类的稳定点停止训练,而不是一些类过拟合,一些类欠拟合的点。

3.2 特征的重要性

当一个新特征被引入到模型中时,我们也想知道它对模型的整体影响。还希望确保模型的预测仍然可以被人类解释,这样可以精确地理解每种数据类型都利用了哪些特征。为此,我们为PyTorch 模型开发了一个每个类的特征重要性。这与通常支持的整体特征重要性不同,因为它并没有告诉我们哪些特征对一个特定的类是重要的。我们通过计算重新组合特征后模型预测误差的增加来衡量一个特征的重要性,如果洗牌后值增加了模型误差,这个特征是 "重要 "的,因为在这种情况下,模型依靠特征进行预测。如果洗牌后模型误差不变,这个特征是 "不重要的",因为在这种情况下,模型忽略了特征进行预测。

每类特征重要性可以使模型具有可解释性,这样可以看到模型关注的是什么。例如要分析地址标签ADDR时,我们会确保与地址相关的特征(如常用小区名某某花园、某某府)在每类特征重要性上排名靠前,以保证人的直觉和模型所学到的东西一致。

3.3 评价

评价是确定衡量成功的标准。我们选择了F2,它提供了一种平衡。召回和精度之间的关系(偏向召回多一点)。对于合规涉及隐私的案例来说,召回率比精度更重要,因为能确保不遗漏任何敏感数据(同时确保合理的精度)。实际上我们模型的F2性能的评估数据超出了本文的范围,尽管如此,通过仔细的调整,我们能够为最重要的敏感类实现较高(0.9+)的F2得分。

4 总结

现有的许多算法都是利用各种技术对非结构化文档进行自动分类。如模式匹配、文档相似度搜索和不同的机器学习技术(贝叶斯技术、决策技术)。任何一种方法都可以作为分类过程的一部分,然而问题在于可扩展性。我们在实践中的分类方法偏重于灵活性和性能,能够在未来支持新的类型,并保持低延迟。

围绕着数据指纹也有一系列的工作。业界对捕捉敏感数据泄露的方案,其假设是有能力对数据进行指纹识别,从而与一组已知的敏感数据进行匹配。但我们关心的数据是高度非结构化的,需要比指纹技术更优的方案。

声明:本文来自唯品会安全应急响应中心,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。