做 OT/ICS 安全研究的人应该都体会过一种无奈想在工控网络流量数据上训练一个入侵检测模型翻了半天开源仓库能用的数据集一只手数得过来。IT 领域有 KDD Cup、CICIDS、UNSW-NB15 这类大规模公开数据到了 OT/ICS 这里能找到的多半是脱敏到只剩包头的 pcap 文件或者连攻击标签都对不上的日志片段。数据稀缺、来源不明、标签不可信这三座大山叠加在一起导致很多人在工业安全方向的算法尝试最后都停在了数据清洗阶段。这篇文章想聊一个正在出现的解法有完整溯源的 OT/ICS 安全训练数据集以及它公开的那 5% 样本到底有什么用。一个很重要的判断是对安全训练数据而言可溯源比规模更重要。数据从哪里来、在什么拓扑上采集、用了哪些协议版本、攻击在哪个时间点注入、标签依据是什么——这些信息决定了你训练出来的模型能否被复现也决定了检测结果能否被信任。文章会从 OT/ICS 数据集为什么稀缺讲起解释 provenanced 到底解决了什么问题然后说明 5% 公开样本的真实价值最后用 Python 演示一个基于公开样本的最小异常检测流程并给出常见问题和工程建议。如果你正在做工业安全分析、想训练工控异常检测模型或者只是需要一份可靠的数据来验证自己的检测思路这篇文章值得收藏后慢慢看。1. 为什么 OT/ICS 安全训练数据集如此稀缺要理解 5% 公开样本的价值先得理解整个 OT/ICS 数据集生态的困境。相比互联网安全领域工控安全数据集的公开程度落后至少五年这不是偶然而是由几个客观因素共同造成的。第一真实工控环境很难开放数据。电力、石油、水处理、制造车间这些关键基础设施运行数据本身就涉及生产安全和商业机密。采集网络流量、PLC 内部寄存器状态、工艺参数变化这些数据的敏感程度远高于普通 IT 日志。就算企业愿意脱敏后公开如何保证脱敏后的数据仍然对安全研究有效本身就是一个棘手问题。很多真实数据在被彻底脱敏之后协议字段、IP 关系、时序特征都发生了变化模型训练出来只能说是证明自己跑通了离实际可用还有很大距离。第二实验室仿真数据的真实性问题。很多公开数据集来自高校或研究机构的测试床例如基于 Modbus TCP、S7comm、DNP3 等协议搭建的小规模仿真环境。这类数据的优点是可以自由设计攻击场景缺点是拓扑规模小、设备类型单一、流量规律性强模型在这样的数据上精度很高换到真实环境就立刻失效。不少做工业异常检测的人都有过类似经历在公开数据集上 AUC 做到 0.99拿到现场数据一测误报率直接爆炸。第三数据集的复现困难症。这也是最容易被忽视的一点。很多数据集的 README 只写了采集时间和攻击类型没有详细说明设备型号、协议版本、网络拓扑、攻击注入的具体时间戳甚至连攻击标签的定义都是模糊的。使用者拿到这样一个 CSV 文件只能看到一行行的数值完全不知道这些数值意味着什么也不知道自己的检测结果应该跟什么基线对比。这种黑盒数据集让很多研究无法被复现也让同领域的比较变得没有意义。正是这三个问题催生了provenanced datasets这个概念。它不是简单地把流量和日志打包发布而是把数据采集的全过程信息也作为数据的一部分公开。2. provenanced 数据集到底在解决什么问题provenance 这个词在数据领域通常翻译为溯源。一个 provenanced 数据集核心特征不是样本多而是每一个样本都能说明自己的来路。我从实际使用的角度拆解一下一个带溯源的安全训练数据集通常包含四个层面的信息。第一层环境拓扑。数据来自什么样的物理或虚拟测试床PLC、RTU、HMI、工程师站怎么连接交换机如何部署是否有旁路监控端口。这些信息决定了你能否理解网络流量的真实路径。同样是 Modbus TCP 流量数据经过了多少跳、是否经过 NAT、有没有中间设备改写包内容特征分布完全不同。第二层设备与协议版本。数据集里包含哪些品牌的 PLC、固件版本是什么、启用了哪些工业协议、协议报文是标准实现还是厂商私有扩展。工控协议的一大特点就是厂商差异大同是 S7comm西门子不同系列 PLC 的行为特征就有区别。协议版本信息直接决定了你的解析器能不能正确从数据中提取特征。第三层攻击场景与标签依据。攻击是在哪个时间点注入的、通过哪个节点发起的、命令序列具体是什么、对工艺过程造成了什么可观测影响。这一层信息最为关键因为标签不是人工臆断出来的而是根植于攻击执行的具体过程。拿到这样的标签你才知道自己模型学到的到底是攻击行为的本质特征还是某些与攻击无关的环境偶然性。第四层数据采集方式。流量是用 tcpdump 在镜像端口抓的还是用 netflow 导出的日志来自 PLC 的诊断接口还是中间件数据有没有做时间对齐、有没有丢包、存储格式是否经过转换。这些细节会影响你对数据质量的判断。为了更直观地说明我把传统数据集和 provenanced 数据集做一个对比对比维度传统安全数据集provenanced 数据集数据来源往往只有一句模糊描述采集环境、拓扑、设备清单可查协议信息只有 pcap 或 CSV协议语义缺失说明协议版本及实现细节攻击标签给出类型但标签时间点不精确攻击注入时间、指令序列、影响可追溯复现难度高数据无法与检测结果关联低同一批数据可重复实验比较主要用途初步验证算法算法验证、结果复现、系统对照另一个容易忽略的点是溯源信息本身就是特征工程的输入。一个安全研究员如果知道数据集中有某型号 PLC 存在固件漏洞就可以针对性地检查该设备通信流中是否存在异常读写操作知道攻击发生在某个时间窗口就可以通过对比窗口前后的协议行为差异来构造更有效的检测特征。没有溯源信息这些分析全部无从下手。3. 5% 公开样本数据集的入口而不是完整数据回到标题里的 5% public sample。初看这是一个克制的发布策略——只公开 5%似乎不够大方。但如果理解上面说的这些溯源信息的生产成本你就会明白这 5% 的设计目标是让使用者评估数据是否适合自己而不是让使用者白嫖核心数据。公开样本的核心价值有四类。价值一是验证数据格式。我们常说看菜下饭在安全数据分析里拿到新数据的第一步永远是确认格式、字段、时间粒度、协议类型。5% 样本足够你跑通读取、解析、特征提取和标签对齐这条完整链路避免申请完整数据后发现格式和自己想的不一样浪费宝贵时间。价值二是评估数据复杂度。源数据集的质量到底如何从 5% 样本里就能看出很多。流量是模拟的还是真实抓取的、协议解析难度大不大、标签覆盖是否完整、是否存在大量未知流量这些特征在抽样数据中同样会体现。价值三是验证自己的分析管线。不少团队做 OT/ICS 安全分析已经沉淀了一套自己的特征提取和检测流程。在公开样本上先跑一遍如果连公开样本的效果都不理想说明算法适配或数据理解还有问题可以尽早调整。这也相当于官方给使用者提供了数据试用装。价值四是建立信任。安全数据领域最大的问题就是互信。数据提供方通过公开 5% 样本让社区检验数据真实性使用者在样本上跑通流程后也更愿意投入资源申请完整数据。这比单纯在论文里放一个下载链接要可信得多。需要注意5% 样本的使用边界也非常明确。它通常不能代表完整数据集的全部攻击类型也不能用于训练一个正式的生产模型更不能作为论文实验的唯一数据来源。它只是一个前期评估工具。完整数据集的获取一般需要经过申请、签署授权协议、确认用途等流程这些流程的设计初衷是保护数据采集方的商业安全和法律责任属于正常行为。从使用者的角度拿到公开样本后最应该做的三件事是读懂元数据、跑通解析流程、确认检测任务是否与数据匹配。如果这三步都顺利再考虑申请完整数据。4. 这类数据集通常包含哪些内容虽然无法说明任何一个具体数据集的内部结构但从 OT/ICS 安全数据的一般构成来看一个成熟的 provenanced 安全训练数据集通常会包含几类互为补充的数据。第一类是网络流量数据。这是整个数据集的骨架常见格式是 pcap 或经过脱敏和特征提取的 CSV 流记录。工业网络流量和普通 IT 流量的区别非常明显动作固定、周期性强、通信关系长期稳定。这使得异常检测通常不需要像互联网安全那样做复杂的流特征工程而是更关注时序规律和协议语义。第二类是设备日志与状态数据。包括 PLC 的诊断日志、HMI 的操作记录、工程师站的组态操作记录。这类数据能帮助研究者理解攻击对现场设备的实际影响。例如一次恶意写寄存器攻击网络层可能只表现为少量写请求但如果结合 PLC 内部状态变化就能做出更准确的判定。第三类是工艺过程数据。比如传感器读数、执行器反馈、PID 控制回路参数。这类数据把网络攻击和物理影响联系起来是 OT/ICS 安全区别于 IT 安全的最大特点。攻击者篡改一个温度设定值最终会导致反应釜压力异常这种物理侧的异常信号可以被独立检测出来。第四类是攻击场景标注文件。通常以 CSV 或 JSON 形式提供记录每一次攻击的起止时间、攻击类型、源地址、目标地址、使用的指令和对应的标签。这部分就是前面反复强调的溯源信息的核心载体也是 provenanced 数据集与普通流量抓取最大的区别。攻击类型方面工业数据集常见的主要有这些网络扫描与服务探测攻击者收集工控网络资产信息。协议重放攻击记录合法指令后原样重发造成重复动作。参数篡改攻击修改 PLC 寄存器或设定值影响工艺过程。拒绝服务攻击通过大量请求或畸形报文让设备无法响应。恶意指令注入直接向 PLC 下发危险的写指令或控制指令。从数据分布来看正常流量通常占绝对多数攻击流量往往只占很小比例。这种极端的类别不平衡是工控安全数据集的普遍特征也是下游建模时必须要处理的挑战。5. 用公开样本跑通一个最小分析流程下面用一个通用示例演示拿到公开样本后如何快速跑通一条最小分析链路。示例不针对任何特定数据集只介绍通用读取方式、异常检测思路和验证方法你拿到实际样本后按数据的结构微调即可。5.1 环境准备建议使用 Python 3.9 及以上版本主要依赖pandas数据读取和处理numpy数值计算scapypcap 报文解析scikit-learn异常检测模型安装命令pip install pandas numpy scapy scikit-learn如果只是处理已经特征化好的 CSV 数据可以不安装 scapy。版本以实际安装为准本文演示的是通用流程。5.2 第一步读取元数据与标签拿到公开样本后不要急着分析报文先看元数据。一个带溯源的数据集通常会在根目录提供 metadata.json 或类似的文件。import json import pandas as pd # 加载元数据理解数据来源 with open(dataset/metadata.json, r, encodingutf-8) as f: meta json.load(f) print(数据集名称:, meta.get(name)) print(采集环境:, meta.get(environment)) print(设备清单:, meta.get(devices)) print(协议列表:, meta.get(protocols)) print(攻击场景数:, len(meta.get(attack_scenarios, [])))输出示例数据集名称: demo_ics_dataset 采集环境: 模拟水处理测试床 设备清单: [PLC-1, PLC-2, HMI, Engineer-Station] 协议列表: [Modbus TCP, EtherNet/IP] 攻击场景数: 3这一步的目的是确认这个数据集与你的研究目标是否匹配。如果对方用 S7comm而你的检测器是给 Modbus TCP 设计的那么继续往后做意义不大。接着读取标签文件labels pd.read_csv(dataset/labels.csv) print(labels.head()) print(正常样本数:, (labels[label] 0).sum()) print(攻击样本数:, (labels[label] 1).sum())标签文件通常包含 flow_id、时间戳、攻击类型、源地址、目标地址等字段。注意先看标签再看流量能够帮助你快速定位攻击事件的时间窗口而不是在茫茫报文中盲目寻找。5.3 第二步解析工业协议流量如果样本中包含 pcap 文件可以使用 scapy 解析。以 Modbus TCP 为例工业协议报文一般运行在 TCP 502 端口上。下面代码演示如何从 pcap 中提取基础连接特征from scapy.all import rdpcap from scapy.layers.inet import TCP, IP cap rdpcap(dataset/traffic/day1_normal.pcap) records [] for pkt in cap: if TCP in pkt and pkt[TCP].dport 502: records.append({ time: float(pkt.time), src_ip: pkt[IP].src, dst_ip: pkt[IP].dst, src_port: pkt[TCP].sport, dst_port: pkt[TCP].dport, pkt_len: len(pkt), tcp_flags: pkt[TCP].flags, }) df pd.DataFrame(records) print(提取到 Modbus TCP 报文数:, len(df)) print(df.head())这段代码先过滤出目标端口为 502 的 TCP 报文然后提取时间、IP、端口、包长和 TCP 标志位。注意工业协议还有可能运行在其他端口上也可能直接使用 UDP实际解析时需要先核对元数据。scapy 对厂商私有协议的解析支持有限如果遇到解析不全的报文优先考虑提取原始字节做特征。5.4 第三步构建窗口级异常检测基线攻击流量不像正常流量那样有稳定的周期性。一个常用的思路是把流量切分成固定时间窗口统计每个窗口的报文数、平均包长、源地址数量等特征再用无监督模型找出异常窗口。import pandas as pd from sklearn.ensemble import IsolationForest # 按 100 个时间窗口做聚合 df[window] pd.cut(df[time], bins100) features df.groupby(window, observedFalse).agg( count(pkt_len, count), avg_len(pkt_len, mean), uniq_src(src_ip, nunique), ).reset_index(dropTrue) model IsolationForest(contamination0.05, random_state42) features[anomaly] model.fit_predict(features) anomaly_count (features[anomaly] -1).sum() print(f异常窗口数量: {anomaly_count})这里使用孤立森林做无监督检测contamination 参数表示先验异常比例。对于公开样本这种小数据量这个检测器能够快速给出一个可评估的基线。但要注意无监督检测出的异常窗口不一定就是攻击窗口还需要与标签文件做对齐检查时间窗口是否覆盖了攻击时间点。如果你想用监督模型可以根据标签文件构造训练集和测试集尝试随机森林或梯度提升树分类。5.5 第四步对齐标签验证检测效果这一步是质量验证的关键。将窗口特征与标签合并按时间戳判断每个窗口是否包含攻击流量然后计算检测的准确率和召回率import pandas as pd # 假设 labels 包含攻击起始时间 attack_start 和结束时间 attack_end # 先用时间窗口边界计算出窗口中心时间再判断是否落在攻击区间内 features[window_start] features[time_min] # 实际情况按窗口左边界计算 # 这里给出简化示例判断窗口内是否有攻击样本 merged pd.merge(features, labels, onflow_id, howleft) print(merged[label].value_counts()) missing_label merged[label].isna().sum() print(f缺失标签的流数量: {missing_label})标签对齐的意义有两个一是验证无监督模型发现的异常是否真的是攻击注入导致二是排查是否存在攻击流量未被模型识别的情况。如果模型在正常窗口产生大量误报可以考虑降低 contamination 参数或者增加窗口特征维度比如加入 TCP 标志位分布、报文长度分位数等。6. 运行结果与效果验证按照上面的流程跑完你应该得到类似这样的输出提取到 Modbus TCP 报文数: 8421 异常窗口数量: 6 正常样本数: 7180 攻击样本数: 1241 缺失标签的流数量: 0这几项数值说明样本集成功读取、协议解析正常、标签完整。此时可以进一步观察攻击窗口的分布情况。判断流程是否成功的标准很简单异常窗口数量不是 0且标签文件中标注的攻击时间段至少有一部分落在异常窗口中。这证明你的分析管线能够捕捉到攻击引起的流量变化。如果异常窗口数为 0优先检查两个地方一是 pcap 解析是否有问题二是窗口时间跨度过大攻击流量被大量正常流量掩盖了。可以尝试把窗口数量增加比如从 100 调到 500让窗口粒度更细。如果运行失败第一步看错误信息。常见的情况是 pcap 文件路径错误、scapy 版本与系统不兼容、或者流量文件中目标端口不是 502。建议先输出前几条原始报文的字段结构确认协议的传输层特征。不要一上来就盲目调模型参数先保证数据链路是通的。7. 常见问题与排查思路基于公开样本分析的典型问题主要集中在协议解析、数据质量、标签对齐三个方面整理如下问题现象可能原因排查方式解决方案解析不到任何工业协议报文报文过滤条件不正确用 Wireshark 打开 pcap 查看协议分布确认协议端口或使用协议名称过滤报文字段缺失使用了厂商私有协议扩展查看 scapy 是否支持该协议用原始字节提取特征标签全部显示正常标签文件与流量时间戳不对齐检查时间戳单位和时区统一时间戳精度为毫秒或秒异常窗口集中在同一时间段数据采集过程本身存在异常查看该时间段的原始报文与数据提供方确认采集过程模型训练结果异常高训练集和测试集存在信息泄露检查是否在分组前做了整体归一化先切分数据再做特征缩放申请完整数据被拒绝用途、机构或授权信息不明确阅读授权协议要求补充研究用途说明签署对方要求的协议关于标签对齐再补充一点有些数据集的攻击标志是以攻击起始时间戳的形式给出而不是给每一条流量打标签。这时你的任务就是把流量记录和攻击时间区间做关联。一个常见的坑是时间戳单位不统一一部分是 Unix 秒一部分是毫秒直接比较就会出现几千倍的偏差。拿到数据后先确认时间戳单位再做对齐。8. 最佳实践与工程建议5% 公开样本虽然小但把它用好对后续完整数据集的使用很有帮助。我基于实践总结了几条建议。第一先写数据理解报告再写检测算法。拿到样本后先用半天时间把元数据、字段、时间分布、协议占比、攻击场景梳理清楚形成一份简单的 Markdown 或 Excel 格式的数据说明。这份说明会成为你判断完整数据质量的基础也能帮助团队成员快速对齐认知。数据理解不深入后面写再多特征工程代码都是空中楼阁。第二把溯源信息纳入特征工程。不要只从报文中提取统计特征。攻击场景文件中标注的攻击类型、执行的指令序列、受影响设备都可以作为特征或验证依据。例如攻击是重放攻击那你的检测器就应该重点观察单位时间内相同功能码报文的重复频次攻击是参数篡改则要结合模拟量从正常范围变化到异常范围的过程。溯源信息能够帮你设计更有针对性的特征而不是盲目堆砌统计量。第三评估指标以工业可用性为准。在工控安全场景中误报率和漏报率同样致命。频繁误报会让现场操作人员最终选择关掉报警漏报则直接威胁生产安全。建议在评估模型时同时关注精确率、召回率、F1 分数甚至模拟不同告警阈值下的效果变化而不是只盯着准确率。对于极端不平衡的安全数据准确率几乎没有参考价值因为全判为正常也能得到很高的数值。第四注意数据合规与授权边界。OT/ICS 安全数据来源特殊即便是公开样本也可能包含敏感信息组织方式、设备型号等细节。使用前务必阅读数据集附带的授权协议确认是否允许二次分发、是否允许用于商业项目、是否需要在论文中致谢或标注来源。生产环境中的自有数据则需要确认采集过程获得了系统负责人授权脱敏处理到位以免造成安全风险。第五搭建可复现的实验流程。建议为样本建立固定目录结构包括原始数据、解析中间结果、特征文件、模型输出、实验报告几个子目录。所有数据处理过程写成脚本记录运行环境依赖版本。这样复现实验结果、对比不同算法效果时才不会陷入 当时的代码忘了哪些包 的窘境。9. 总结与后续学习方向OT/ICS 安全训练数据集稀缺的根源不在技术而在数据采集成本和信任机制。provenanced 数据集通过公开完整的采集环境、设备清单、攻击场景和时间戳把数据来源变成数据本身的一部分从根上解决了数据可信度问题。而 5% 的公开样本则给使用者提供了一个低成本的评估入口格式是否合适、标签是否可靠、任务是否匹配跑一遍样本就能判断不需要盲目申请完整数据。对开发者而言接下来的实践路径可以分三步走先在公开样本上跑通数据读取、协议解析、标签对齐全流程再基于样本尝试一两个工业安全场景的检测方法比如异常流量检测或设备状态异常识别最后根据自己所在行业的具体业务场景构建针对性的验证集逐步将数据使用经验沉淀为团队内部的可复用工具。如果未来能在更多领域看到这种样本公开、完整数据授权模式整个工业安全研究社区都会受益。对研究者来说数据不再是一个只出现在论文附录里的黑箱而是可以被理解、被检验、被复现的研究基础设施。希望这篇文章能帮你把 5% 的公开样本用起来迈出这一步。