第六章:基于 AI 的网络异常检测

当前可以在不同设备之间建立的互联互通水平(例如,考虑到物联网IoT))已达到如此复杂的程度,以至于严重质疑传统概念,如边界安全的有效性。实际上,网络空间的攻击面呈指数级增长,因此,必须借助自动化工具来有效地检测与前所未有的网络安全威胁相关的网络异常。

本章将涵盖以下主题:

  • 网络异常检测技术

  • 如何分类网络攻击

  • 检测僵尸网络拓扑

  • 不同的机器学习ML)算法用于僵尸网络检测

在本章中,我们将重点讨论与网络安全相关的异常检测,将欺诈检测和用户异常行为检测的讨论推迟到后续章节。

网络异常检测技术

我们迄今为止所看到的技术也可以应用于管理异常检测以及相关的未授权访问企业网络的尝试。为了充分理解异常检测技术的潜力,我们将追溯其在网络安全领域的发展,阐明其基本原理。

实际上,异常检测一直是网络安全领域的研究方向,尤其是在网络安全保护领域。然而,异常检测不仅仅局限于识别和防止网络攻击,它还可以在其他领域中应用,比如欺诈检测和用户资料的潜在泄露识别。

异常检测的原理

在网络入侵检测领域,特别是长期以来,采取了以下两种不同的策略:

  • 基于签名的检测

  • 异常检测

在第一种情况下,我们从已知攻击的分析开始,构建一个由之前检测到的攻击签名组成的知识库。这与警报系统结合,一旦网络流量中出现与归档签名的匹配,即可触发警报。基于签名的检测系统与各种杀毒软件的类比显而易见,缺点同样明显,因此,签名知识库必须不断更新,以便检测新的攻击类型。

在异常检测的情况下,另一方面,我们尝试识别可以定义为正常的网络流量行为,以便检测那些偏离正常行为的差异,即将其识别为异常。因此,这种方法使得通过分析可能被认为是异常的网络流量特征来检测新型攻击成为可能。

因此,有必要识别出什么构成异常行为,特别是针对网络流量的异常行为。

为了检测异常流量,可以考虑以下一些元素:

  • 到特定主机的连接数量

  • 不寻常的远程通信端口或意外的流量模式

  • 特定时间段内出现的不寻常流量高峰(例如,夜间持续的流量)

  • 网络中由特定主机占用的大量通信带宽

所有这些事件可能会被视为可疑,基于之前对被认为是正常的网络流量进行的分析。这种比较的基础是,可以定义适当的过滤器并将警报信号(警报)与它们关联,一旦触发,甚至可以决定丢弃相应的网络流量。

显然,还需要考虑与可疑行为无关的新型网络流量。例如,如果添加了以前没有的新通信通道,这种变化必须被考虑,并视为正常。

因此,正如我们将看到的,异常检测的一个敏感方面是区分真正的正例和假正例。

入侵检测系统

传统上,入侵检测活动通过引入专门的设备来管理,这些设备被称为入侵检测系统IDS)。这些设备通常被分为以下两类:

  • 基于主机的 IDS

  • 基于网络的入侵检测系统

随着人工智能AI)技术在网络安全领域的引入,第三种类型的 IDS——基于异常的 IDS——也加入了前述的两种传统类型。

为了充分理解基于异常的入侵检测系统(IDS)的区别和优势,简要描述两种传统类型的 IDS 是适当的。

主机入侵检测系统

主机入侵检测系统HIDS)的任务是检测可能影响组织内主机的入侵,尤其是那些被认为是关键的机器。为此,HIDS 监控一些被认为对识别可能攻击至关重要的系统指标,如与以下系统指标相关的系统信息:

  • 正在运行的进程的数量和类型

  • 用户账户的数量、类型和创建情况

  • 内核模块加载(包括设备驱动程序)

  • 文件和目录活动

  • 任务调度器活动

  • 注册表键值修改

  • 后台进程(守护进程和服务)

  • 操作系统OS)在启动时加载的模块

  • 主机网络活动

通常,待监控的系统指标的识别严格依赖于所采用的威胁模型,并且为了收集待监控的信息,可以使用操作系统自带的工具,或通过安装专门的系统监控工具。

网络入侵检测系统

网络入侵检测系统NIDS)的典型任务是通过分析网络流量来识别可能的攻击模式;也就是说,通过处理传输中的网络数据包——包括进站和出站数据——并在数据流中检测已知的攻击模式。

NIDS 通常检测到的网络攻击如下:

  • 广告软件(导致来自远程主机的未经请求和恶意的广告AD)下载)

  • 间谍软件(向远程主机传输敏感信息)

  • 高级持续性威胁APT)(APT 针对特定组织漏洞或配置错误服务的攻击)

  • 僵尸网络(典型的指挥与控制C2)攻击,通过将主机转变为僵尸机器并执行远程指令来利用组织的网络资源)

tcpdump

NIDS 还可以部署集成软件解决方案,如 Snort,这代表了实时检测可能的网络入侵的有效解决方案。

这有助于根据特定规则来定义,在此基础上可以比较正常和恶意的网络流量,从而在攻击被识别后激活触发器,执行适当的操作。

通常,这些触发器与给定的阈值相关联,这是一个预定值,它可靠地区分它们之间的事件。显然,如何充分确定该阈值值的问题就出现了,且该值是否可以有效地用于不同上下文下。以同样的方式,攻击者可能尝试修改此阈值,或发现这个值实际上被设置成什么,尝试采用隐形访问模式(通过保持活动始终低于阈值),使自己对 IDS 不可见。

因此,更优的做法是采用动态阈值(而不是依赖硬编码的值),通过系统地重新计算其值来随时间变化。这些改进可以通过采用基于时间序列(移动平均)的统计度量来获得,例如,或者通过对数据分布的统计测量重新处理(例如,采用位置测量如中位数或四分位间距IQR))。

尽管有用,但这种统计方法用于确定触发阈值在最复杂的入侵检测案例中不可避免地无效,因为它需要考虑不同变量之间可能存在的相关性。

换句话说,在某些场景中,可能需要同时触发多个触发阈值,因为异常在相互关系中由不同特征表示。

鉴于网络数据流的复杂性,因此有必要引入有状态检查——也称为数据包过滤活动——作为与常见网络监控(旨在提取不同类型数据包的信息)分开的过程。

通过跟踪传输和接收的各种数据包,有状态检查的特点在于能够关联不同类型的数据包,以识别针对某些网络服务的连接尝试、网络资源的饱和攻击(拒绝服务攻击DoS))或在更低网络协议层次进行的攻击(如 ARP 缓存中毒)。

由于其先进的网络分析功能,有状态检查可以与更复杂的异常检测形式结合使用。

基于异常的 IDS

随着人工智能技术的引入,NIDS(网络入侵检测系统)领域现在可以将传统的 IDS 发展为更先进的检测解决方案,利用监督学习和无监督学习算法,以及强化学习和深度学习。

同样,前几章分析的聚类技术,利用了数据类别之间的相似性概念,可以有效地用于基于异常的入侵检测系统(IDS)的实现。

然而,在选择用于异常检测网络的算法时,必须考虑网络环境的一些特征性方面:

  • 在基于监督学习算法的解决方案中,我们必须对所有数据进行分类(标记),因为按定义,监督学习中样本数据所属的类别是已知的。

  • 所有数据的分类不可避免地会涉及计算过载,并可能导致网络性能下降,因为在发送到目标之前,网络流量必须进行分析。从这个角度来看,我们可以决定采用无监督学习算法,不仅让算法识别未知类别,还能减少计算开销。

类似地,利用相似性概念的算法(如聚类算法)非常适合用于实现异常检测解决方案。然而,在这种情况下,同样需要特别注意用于定义相似性概念的度量类型,这些度量能够区分正常流量与异常流量。

通常,在实施异常检测解决方案时,会使用评分系统来评估流量:确定分隔不同类型流量(正常与异常)之间的值阈值。为此,在选择最合适的度量时,我们必须考虑数据的排序和分布。

换句话说,异常检测系统可以使用——作为评分指标——数据集值之间的距离(这些值被视为代表不同特征的n维空间中的点),或评估数据分布的规律性,依据的是被认为是研究现象代表性的分布。

将服务日志转化为数据集

网络异常检测的一个问题是如何收集足够且可靠的数据来进行算法分析和训练。互联网上有数百个免费提供的数据集,可以用于我们的分析;然而,我们也可以使用自己的网络设备来积累更能代表我们特定现实的数据。

为此,我们可以使用以下方法:

tcpdump
/var/log%SystemRoot%\System32\Config

无论是类 Unix 系统还是 Windows 操作系统,日志文件都是基于预定义模板的文本格式,唯一不同的是,在 Windows 中,每个事件在相应的日志文件中都会关联一个事件 ID。日志文件的文本性质非常适合集成存储在日志中的信息。

集成网络数据与服务日志的优势

两个数据源,即网络数据和服务日志,在网络异常检测中各有优缺点。

然而,它们的集成使得可以在利用优势的同时,限制其缺点。

近年来,发布了多种软件解决方案(包括专有软件和开源软件),这些解决方案旨在解决集成不同数据源的问题,使用户能够利用数据科学和大数据分析的方法进行分析,这并非偶然。

在最广泛的解决方案中,我们可以提到ElasticSearch, Logstash, KibanaELK)套件,它可以对从日志文件中提取的事件进行索引,并以直观的可视化形式表示。

其他广泛使用的专有网络解决方案基于 Cisco 的 NetFlow 协议,它可以紧凑地表示网络流量。

从原始数据重构感兴趣的事件是非常困难的。更重要的是,如果以自动化的方式进行处理,这可能会导致生成不可靠的信号(误报),这代表了安全管理中的一个问题。

此外,在网络数据的情况下,它们代表了各个相关服务,而在服务日志的情况下,它们直接与生成它们的进程相关。

因此,整合两种数据源(网络数据和服务日志)可以实现对正在分析事件的上下文化,进而提高上下文意识,并减少从原始数据开始解读事件所需的努力。

如何分类网络攻击

我们已经看到,可以使用各种不同类型的算法(如监督学习、无监督学习和强化学习),即使是在实施网络异常检测系统时。

那么我们如何有效地训练这些算法,以便识别异常流量呢?

首先需要识别一个代表给定组织内正常流量的训练数据集。

为此,我们必须适当地选择代表我们模型的特征。

特征选择尤为重要,因为它们为所分析的数据提供了上下文价值,从而决定了我们检测系统的可靠性和准确性。

事实上,选择那些与可能的异常行为相关性不高的特征会导致较高的错误率(误报),因此会使它们失去效用。

选择可靠特征的一种解决方案是评估现有的网络协议使用中的异常。

攻击——例如 SYN 洪水攻击——的特征是 TCP/IP 握手的异常使用(在这种情况下,设置 SYN 标志的数据包后面没有跟随设置 ACK 标志的数据包,从而无法建立有效连接)。

23

最常见的网络攻击

鉴于我们可以通过组合不同的特征来识别的各种组合的巨大多样性,必须依赖一个反映给定组织所面临风险水平的威胁模型,并在此模型的基础上,识别出最具代表性的特征组合,以便应对可能的攻击。

从这个角度来看,分析最常见的网络攻击类型是有用的:

  • 基于恶意软件的

  • 零日漏洞

  • 通过网络嗅探进行数据泄漏

  • 网络资源饱和(DoS)

  • 会话劫持

  • 连接欺骗

  • 端口扫描

基于类似的分类(需根据具体上下文进行调整并不断更新),我们可以识别需要考虑的特征,将更具代表性的数据集输入到我们的算法中。

异常检测策略

因此,我们已经看到,异常检测的概念本身指的是与预期行为不同的表现;这种差异,从技术角度来说,就是离群点检测。

要识别离群点,可以采取不同的策略:

  • 分析时间序列中的事件序列:数据在定时间隔内收集,评估序列随时间发生的变化。这种技术广泛应用于金融市场分析,但也可以有效地应用于网络安全领域,用于检测用户在远程会话中输入字符(或命令)的频率。即使是每单位时间内输入数据频率的简单不自然增加,也可以表明存在异常,这可能表明远程端点中存在自动化代理(而非人工用户)。

  • 使用监督学习算法:当正常行为与异常行为可以可靠地区分时,这种方法是有意义的,例如在信用卡欺诈的情况下,可以检测到预定义的可疑行为模式,依赖于未来的欺诈行为可以归因于一个预定义的方案。

  • 使用无监督学习算法:在这种情况下,无法将异常行为追溯到预定义的行为,因为无法识别出可靠且具有代表性的训练数据集用于监督学习。这种场景最常描述网络安全的现实,特征是新的攻击形式或新漏洞的利用(零日攻击)。同样,通常也很难将所有理论上可能的入侵归结为一个预定义的方案。

异常检测假设与挑战

从方法论角度来看,毫无疑问,离群点是学习算法的一个问题,因为它们在基于训练数据构建描述性模型时构成了干扰因素。

当处理异常值时,算法应如何处理?是应该考虑模型的判定,还是应该将其丢弃,视为估计误差?或者,离群点是否代表数据集中反映出实际变化的创新现象?要回答这些问题,我们需要调查离群点的最可能来源。

在某些情况下,异常值是不同寻常值的组合,它们是估计误差,或者源自多个具有不同语义的数据集的合并,导致不可靠或极不可能的样本。然而,它们的存在却构成了一个干扰因素,特别是对于那些基于估计预期值与观察值之间距离的度量的算法而言。从技术角度讲,这意味着整体方差增加,可能导致算法高估误差,从而影响信号的正确性(这一现象被称为过拟合)。

显然,并不是所有算法对异常值的存在都同样敏感。然而,良好的做法是尽量使学习过程更具鲁棒性,通过平滑参数更新阶段,给那些尽管在数值上低于正常值但可能会影响正确参数估计的异常值加权。

为了识别数据集中可能存在的异常值,通常做法是进行数据的初步分析,这被称为探索性数据分析EDA),利用可视化工具并计算简单的描述性统计量(如均值或中位数)。

通过这种方式,可以直观地发现异常值的存在,并验证数据中的任何不对称性,表现为分布中均值与中位数之间的距离逐渐增大。

一些统计度量对极端值的存在不那么敏感。事实上,旨在表示数据排序的度量对于分布中的异常值具有更强的鲁棒性(例如四分位间距 IQR)。

因此,异常值检测的一个基本假设是数据集中正常观测值远多于异常观测值。然而,事实是,通常正确识别异常值并不是一项容易完成的任务。

从这个角度来看,如果我们决定使用统计度量来确定异常值的存在,我们可以按照以下步骤进行操作:

  1. 计算代表数据的统计值,用作对比标准,以确定异常值(即,最偏离代表性值的那些值)。

  2. 确定一个异常检测的参考模型,这个模型可以基于距离度量,或者假定已知的统计分布(即正态分布)作为正常值的代表。

  3. 定义置信区间并评估异常值存在的概率(可能性),基于所选择的分布。

统计方法用于识别异常值,虽然容易且直接应用,但仍然存在重要的理论限制:

  • 大多数统计检验只考虑单一特征。

  • 通常,数据的底层分布是未知的,或者不能归因于已知的统计分布。

  • 在复杂且多维的案例中(其中必须同时考虑多个特征),离群值的存在会导致总方差的增加,使得所识别的代表性模型在预测上变得不那么显著。

检测僵尸网络拓扑

网络异常检测中最常见的陷阱之一与在企业网络内检测僵尸网络有关。由于这些隐藏网络的危险,检测僵尸网络尤其重要,不仅是为了防止外部攻击者耗尽组织的计算和网络资源,还为了防止敏感信息的泄露(数据泄漏)。

然而,及时识别僵尸网络的存在往往是一个复杂的操作。这就是为什么理解僵尸网络的本质非常重要。

什么是僵尸网络?

僵尸网络这一术语来源于botnet两个词的组合。对于“net”一词,我们显然需要处理网络的概念;而对于“bot”一词,我们则需要再多说几句。

“Bot”一词实际上越来越与自动化代理在网络空间中的传播相关联。

聊天机器人(通常在网站上用于管理客户服务初期阶段的软件代理,但也越来越广泛,甚至在社交网络上为各种目的使用)到网络喷子(旨在通过传播虚假信息分散用户注意力或困惑用户的软件代理),网络空间正日益被这些自动化的、在人与数字设备之间进行交互的软件代理所感染。

在僵尸网络的情况下,攻击者的意图是通过安装恶意软件将受害主机转变为自动化代理,通过通常由集中式服务器管理的 C2 控制台接收并执行攻击者的命令。

受害机器因此成为一个庞大的受感染机器网络(僵尸网络)的一部分,通过其计算和网络资源贡献共同目标:

  • 参与电子邮件垃圾邮件活动

  • 对机构或私人第三方网站执行分布式拒绝服务DDoS)攻击

  • 比特币和加密货币挖矿

  • 密码破解

  • 信用卡破解

  • 数据泄漏和数据泄露

对于一个组织来说,处理一个僵尸网络(即使是不自觉地)代表着在法律责任方面对第三方的重大风险;这不仅仅是公司资源的浪费。

因此,重要的是监控公司网络,尽早识别可能属于僵尸网络的主机。

僵尸网络杀伤链

为了及时识别僵尸网络的可能存在,考虑其攻击链(实现过程中的不同阶段)可能是有益的。

因此,我们可以区分以下阶段:

  • 恶意软件安装

  • 通过 C2 加入僵尸网络

  • 将僵尸网络传播到其他主机

80

在僵尸网络的情况下,受害主机必须不断呼叫主控服务器(C2),以接收新命令并将收集到的信息以及在受害系统上执行的进程结果发送给 C2 服务器。

这种现象被称为信标现象,其特征正是网络中存在定期(即使在非工作时间)进行连接的行为,这些连接发生在感染的主机与远程目标之间(这些远程目标也可能是被攻击者妥协的合法网站)。

信标现象通常以以下特点为特征:

  • 长期的用户会话,交换空包(保持连接的空包),以保持连接的打开

  • 主机之间定期的数据交换

信标现象的问题在于它不能总是可靠地识别;因此,它构成了僵尸网络存在的一个症状,因为其他合法服务也可能表现出类似之前提到的特征。为了捕获能够证明真实信标过程存在的可靠信号——并将其与良性的 SSH 或 telnet 会话区分开来,以及与抗病毒软件执行的系统更新下载过程区分开来——因此需要深入的网络流量监控,并结合时间序列的统计分析和位置度量的计算,如中位数和 IQR,以便识别那些定期发生的通信。

随后,必须通过图形化的方式展示这些本地和远程主机的映射,以便识别可能具有稳定特征的网络拓扑,并合理地引发对僵尸网络存在的怀疑。

从对必要的初步分析活动的描述中,很容易推断出在被误判为僵尸网络而非真实僵尸网络的网络中,存在被误报的风险,特别是在潜在的设备数量(它们持续连接到网络)呈指数增长时(这一情景比以往任何时候都更为现实,因为物联网的普及)。

用于僵尸网络检测的不同机器学习算法

从我们迄今为止描述的内容来看,显然不建议仅依赖自动化工具进行网络异常检测,采用能够动态学习如何识别网络流量中异常存在的人工智能算法可能更为高效,这样可以使分析师对仅真正可疑的案例进行深入分析。接下来,我们将展示不同的机器学习算法在网络异常检测中的应用,这些算法也可用于识别僵尸网络。

我们示例中选择的特征包括网络延迟和网络吞吐量的值。在我们的威胁模型中,与这些特征相关的异常值可以视为僵尸网络存在的代表。

对于每个示例,都会计算算法的准确度,以便能够对比所获得的结果:

import numpy as np
import pandas as pd

from sklearn.linear_model import *
from sklearn.tree import *
from sklearn.naive_bayes import *
from sklearn.neighbors import *
from sklearn.metrics import accuracy_score

from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt
%matplotlib inline

# Load the data
dataset = pd.read_csv('../datasets/network-logs.csv')

samples = dataset.iloc[:, [1, 2]].values
targets = dataset['ANOMALY'].values

training_samples, testing_samples, training_targets, testing_targets =
train_test_split(samples, targets, test_size=0.3, random_state=0)

# k-Nearest Neighbors model
knc = KNeighborsClassifier(n_neighbors=2)
knc.fit(training_samples,training_targets)
knc_prediction = knc.predict(testing_samples)
knc_accuracy = 100.0 * accuracy_score(testing_targets, knc_prediction)
print ("K-Nearest Neighbours accuracy: " + str(knc_accuracy))

K-Nearest Neighbours accuracy: 95.90163934426229

# Decision tree model
dtc = DecisionTreeClassifier(random_state=0)
dtc.fit(training_samples,training_targets)
dtc_prediction = dtc.predict(testing_samples)
dtc_accuracy = 100.0 * accuracy_score(testing_targets, dtc_prediction)
print ("Decision Tree accuracy: " + str(dtc_accuracy))

Decision Tree accuracy: 96.72131147540983

# Gaussian Naive Bayes model
gnb = GaussianNB()
gnb.fit(training_samples,training_targets)
gnb_prediction = gnb.predict(testing_samples)
gnb_accuracy = 100.0 * accuracy_score(testing_targets, gnb_prediction)
print ("Gaussian Naive Bayes accuracy: " + str(gnb_accuracy))

Gaussian Naive Bayes accuracy: 98.36065573770492

高斯异常检测

检测数据分布规律性最广泛使用的一种方法是利用高斯概率分布。

正如我们所看到的,这种统计分布具有一系列有趣的特性,帮助我们适当建模许多自然、社会和经济现象。

显然,并非所有待研究的现象都可以用高斯分布表示(正如我们所看到的,分析现象的基础分布往往是未知的);然而,在许多异常检测的案例中,它仍然是一个可靠的参考点。

因此,我们必须了解高斯分布的特性,才能理解为什么它被广泛使用。

高斯分布

从数学角度来看,高斯分布(也称为正态分布)表示随机变量的概率分布,其数学形式如下:

在这里,µ表示均值,σ²表示方差(它代表数据围绕均值的变化性)。在其标准形式中,均值µ0σ^(2)为1

高斯分布的优势在于中心极限定理,简单来说,它确立了随机变量的观察数据的平均值——独立提取的——随着观察次数的增加会收敛到正态值。

换句话说,随着观察次数的增加,这些观察值会围绕均值µ对称分布(且具有更高的概率):

当偏离平均值(趋向于分布在左右极端)时,随着σ值的增加,正态分布因此由µσ所假定的值充分表示。

同样,可以确定观察值围绕平均值分布的概率,这与方差的值成比例;换句话说,我们可以确定以下内容:

  • 68%的观察值落在µ - σµ + σ之间

  • 95%的观察值落在µ - 2σµ + 2σ之间

  • 99.7%的观察值落在µ - 3σµ + 3σ之间

使用高斯分布进行异常检测

高斯分布可以用来识别异常值。此外,在这种情况下,异常元素由与其余数据相比,异常值的显著差异所组成。

显然,数据的大多数值越是紧密集中在均值µ周围,且方差σ较低,越能使异常值的差异变得更加显著。

为了在异常检测中使用高斯分布,我们需要执行以下步骤:

  1. 假设训练集的特征服从正态分布(这一点也可以通过对绘制数据的直观分析来验证)

  2. 估算µσ值,代表该分布

  3. 选择一个合适的阈值,代表观察值为异常的概率

  4. 评估算法的可靠性

在以下示例中,我们将展示高斯异常检测的实现。

高斯异常检测示例

.csv
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

dataset = pd.read_csv('../datasets/network-logs.csv')

数据加载到内存后,我们验证样本的分布是否可能类似于高斯分布,并以直方图的形式显示相应的值:

hist_dist = dataset[['LATENCY', 'THROUGHPUT']].hist(grid=False, figsize=(10,4))

前面的代码生成以下输出:

在这一点上,我们在散点图上进行数据绘制,直观地识别出可能的异常值:

data = dataset[['LATENCY', 'THROUGHPUT']].values

plt.scatter(data[:, 0], data[:, 1], alpha=0.6)
plt.xlabel('LATENCY')
plt.ylabel('THROUGHPUT')
plt.title('DATA FLOW')
plt.show()

前面的代码生成以下输出:

从视觉上看,绝大多数观察值集中在平均值周围,只有一些例外。因此,我们希望验证异常情况是否属实,然后继续估算潜在高斯分布的代表性值µσ

"""
Anomaly Detection Module
Thanks to Oleksii Trekhleb:
https://github.com/trekhleb/homemade-machine-learning/blob/master/homemade/anomaly_detection/gaussian_anomaly_detection.py
"""
from gaussian_anomaly_detection import GaussianAnomalyDetection

gaussian_anomaly_detection = GaussianAnomalyDetection(data)

print('mu param estimation: ')
print(gaussian_anomaly_detection.mu_param)

print('\n')

print('sigma squared estimation: ')
print(gaussian_anomaly_detection.sigma_squared)

mu param estimation:  
[14.42070163 15.39209133]

sigma squared estimation: 
[2.09674794 1.37224807]

接下来,我们估算概率和阈值,然后进行比较,以识别异常数据:

targets = dataset['ANOMALY'].values.reshape((data.shape[0], 1))
probs = gaussian_anomaly_detection.multivariate_gaussian(data)

(threshold, F1, precision_, recall_, f1_) =
gaussian_anomaly_detection.select_threshold(targets, probs)

print('\n')

print('threshold estimation: ')
print(threshold)

threshold estimation: 
0.00027176836728971885

在这一点上,我们可以通过将各个样本的概率与先前估算的最优阈值进行比较,从而识别异常值,并在散点图中可视化它们的存在:

outliers = np.where(probs < threshold)[0]
plt.scatter(data[:, 0], data[:, 1], alpha=0.6, label='Dataset')
plt.xlabel('LATENCY')
plt.ylabel('THROUGHPUT')
plt.title('DATA FLOW')

plt.scatter(data[outliers, 0], data[outliers, 1], alpha=0.6, c='red', label='Outliers')

plt.legend()
plt.plot()

前面的代码生成以下输出:

现在是对算法进行估计的时候了。但首先,我们需要介绍一些与异常检测中误报识别相关的概念。

异常检测中的误报管理

我们之前已经看到异常检测会导致相当一致的估计误差。特别是在基于签名的 IDS 案例中,错误的风险由较高数量的假阴性表示,即未检测到的攻击。

当使用反病毒软件时,我们面临相同类型的风险。如果没有与可疑签名的对应,IDS 将不会检测到任何异常。

另一方面,在基于异常驱动的 IDS 案例中,该系统被编程为自动检测异常,我们面临着高假阳性数量的风险;即检测到的异常实际上并非有害。

要适当地管理这些误报,我们需要引入一些度量标准,这些度量标准将帮助我们估计这些错误。

第一个是真正率(也称为灵敏度或召回率):

Sensitivity or True Positive Rate (TPR) = True Positive / (True Positive + False Negative);

然后,我们有假正率

False Positive Rate (FPR) = False Positive / (False Positive + True Negative);

Precision = True Positive / (True Positive + False Positive);
F1PrecisionSensitivity
F1 = 2 * Precision * Sensitivity / (Precision + Sensitivity);
F11F10F1
F1
print('F1 score: ')
print(F1)

F1 score: 
0.6666666666666666
F11F1

接收器工作特性分析

scikit-learnroc_curve()
from sklearn.metrics import roc_curve

FPR, TPR, OPC = roc_curve(targets, probs)
TPRFPROPC
TPROPC
# Plotting Sensitivity

plt.plot(OPC,TPR)

前述代码生成以下输出:

TPROPC
TPRFPR
# Plotting ROC curve

plt.plot(FPR,TPR)

上述代码生成了以下输出:

摘要

在这个日益互联的世界中,随着物联网(IoT)的逐步普及,有效分析网络流量以寻找可能代表安全漏洞的异常变得至关重要(例如,僵尸网络的存在)。

另一方面,单纯依赖自动化系统进行网络异常检测任务会使我们面临管理越来越多误导性信号(假阳性)的风险。

因此,将自动化异常检测活动与人工操作员进行的分析相结合,利用 AI 算法作为过滤器,选择那些真正值得分析人员深入关注的异常,显得更加合适。

在下一章,我们将讨论用于保护用户认证的 AI 解决方案。

第三部分:保护敏感信息和资产

本节涵盖了通过生物识别认证、登录尝试分类、账户速度特征和声誉评分来防止认证滥用和欺诈。

本节包含以下章节:

  • 第六章,用户认证的安全性

  • 第七章,利用云 AI 解决方案防止欺诈

  • 第八章,生成对抗网络 (GANs)攻击与防御

第七章:确保用户身份验证的安全

在网络安全领域,人工智能AI)在保护用户敏感信息方面扮演着越来越重要的角色,包括他们用于访问网络账户和应用程序的凭证,以防止身份盗窃等滥用行为。

本章将涵盖以下主题:

  • 防止身份验证滥用

  • 账户声誉评分

  • 用户身份验证通过击键识别

  • 人脸识别生物识别身份验证

防止身份验证滥用

在当前这种日益去中心化的背景下,传统服务逐渐以数字形式提供(如电子商务、网上银行等),正确识别并防止可能针对用户数字身份的威胁变得尤为重要,例如身份盗窃的风险。此外,随着物联网IoT)的迅速发展,通过伪造凭证(或从合法拥有者处盗取凭证)获得未经授权的访问权限的可能性比以往任何时候都更高。

这是由于网络空间的维度及其增加的攻击面所致,网络空间的攻击面由可以在人与机器之间以及机器与机器之间建立的连接数量的指数级增长所决定,这使得信息泄露的风险更大。

保护用户账户不仅是数据完整性的问题,也是任何企业的声誉风险,因为这可能会引发对第三方的法律责任。

只需想想有关虚假账户扩散的问题,这些账户是故意创建的,目的是获取用户的机密和敏感信息。还有恶搞账户的问题,它们可能会混淆和误导那些不知道这些虚假账户性质的合法用户。

随着自动化服务的普及,这些服务越来越多地由算法管理,从法律角度来看,确保通过自动化程序收集的敏感信息的正确性和合法性变得至关重要;企业可能会根据欧盟的通用数据保护条例GDPR)所确立的责任原则被要求承担相应责任。

因此,必须采取所有必要的组织措施,以确保用户账户的安全,这通过监控可疑活动来实现,例如试图破解密码的行为。

保护用户账户的一个弱点是密码保护不足。

密码是否已经过时?

密码一直是确保用户账户安全的主要工具;然而,它们已经暴露出自己的局限性。

随着在线服务数量的增加(以及用于访问这些服务的不同平台的增多),用户必须记住的密码数量也随之增加。

由于构成可靠密码的字母数字代码的强度与其易于管理性相对立,用户常常为多个账户和服务使用相同的密码。

这有助于攻击面扩大,从而增加被入侵的风险。如果攻击者成功窃取了用户的凭证(例如,他们的个人电子邮件账户),那么他们很可能也能破坏其他凭证,因此成功窃取受害者的数字身份。

身份盗窃的风险,实际上是用户可能面临的主要威胁之一。一旦受害者的身份被侵犯,攻击者便可以展开一系列非法活动,比如通过以受害者名义开设银行账户进行洗钱,这一切都以受害者的凭证为掩护,而受害者往往对这些非法活动一无所知。

随着时间的推移,采纳集成密码认证和账户授权程序的安全措施并非偶然。这些措施部署了旨在提高上下文意识的监控任务,也就是说,分析和界定与使用访问凭证相关的活动,在对个体用户来说,处于正常(或可疑)情境中的活动。

保护用户账户不仅仅限于验证输入密码的正确性及密码与用户账户的一致性,还包括记录的各种账户活动,如来自不同地理区域的 IP 地址的同时访问,或者使用不同的设备,如 PC、智能手机、浏览器和操作系统,这些都是不常见的或之前从未使用过的。

这一监控的目标显然是检测攻击者可能通过利用之前被泄露的密码来访问用户账户,进而窃取凭证。

为了实现这种水平的上下文安全意识,必须将发生在用户账户上的监控活动与使用自动学习算法的异常检测程序结合,从而根据用户的习惯和行为学习区分不同的可疑活动。

还可以用身份验证程序来替代相同的密码,这些程序利用用户的生物识别凭证,如虹膜、声音、指纹或面部特征。

在这种情况下,将识别程序限制为单一生物特征证据并不合适,尽管它是强大的,但仍然是可以被伪造的(可以通过利用用于验证生物特征数据的传感器的局限性和漏洞来伪造)。相反,我们应当将其与其他验证用户凭据的方法结合起来。

常见的认证实践

为了确保凭据确实属于账户的合法拥有者,随着时间的推移,已经引入了各种形式的验证,其中一些基于采用第二重认证因素,如插入通过短信传送到用户电话号码的临时密码,或者通过与用户账户关联的电子邮件地址发送的 OTP 验证码。这类程序的可靠性基于次要因素,如用于接收和管理这些认证因素的支持和通道的完整性。

如果用户的电子邮件账户被黑客入侵,或者智能手机上安装了恶意软件,该恶意软件会自动转发短信验证码(OTP)给攻击者,那么第二重认证因素在安全方面的无效性就显而易见。

第二重认证因素的有效性假设基于所使用支持的多样化。换句话说,建议用户不要将所有个人敏感信息都保存在同一支持中(遵循其中一种最知名的风险管理最佳实践,即不要把所有的鸡蛋放在同一个篮子里)。

如果这种多样化假设未被验证,那么基于第二重认证因素的认证程序的可靠性也必然会失效。

如何识别虚假登录

从我们到目前为止所说的内容来看,应该清楚的是,基于安全令牌的认证程序,如密码、短信、OTP 等,至少应与自动化的异常检测程序结合使用。

与用户账户管理相关的异常之一是:

  • 暴力破解访问尝试,旨在通过在有限时间内输入不同的密码来识别用户的密码

  • 来自不同地理区域的 IP 地址的同时访问

  • 用户使用不常见的设备、软件和操作系统

  • 与人工操作员不兼容的频率和打字速度

显然,待监控事件的列表可以根据具体的分析背景增加和变化。然而,一旦提供了代表性事件的历史基础,自动检测异常是非常重要的。

虚假登录管理——反应式与预测性

一旦与可疑访问相关的代表性事件积累起来,了解所要遵循的管理策略就变得至关重要。

更传统的方式是配置反应式报警系统;也就是说,一旦发现可能的未经授权访问,报警系统会触发事件(反应),并自动暂停或封锁用户账户。

虽然反应策略实施起来较为简单,但它会带来以下重要的副作用和缺点:

  • 拒绝服务DoS)攻击可能会针对合法用户;攻击者通过模拟未经授权的访问尝试来触发报警系统自动封锁用户账户,从而损害组织的声誉,增加对用户和提供服务的公司造成的干扰。

  • 反应式报警系统通常设有与相关事件相关的默认触发器。事件的校准是针对所有用户全局进行的,系统不会根据用户的特定行为来识别单个用户。

  • 反应策略通过后视镜来看现实,即假设未来和过去一样,因此不能自动适应上下文的快速变化。

  • 反应策略通常基于对异常活动峰值的监控,即如果行为超过了被认为是正常的某个预设水平,则被认为是可疑的。这种情况发生在隐秘模式下进行的攻击中,攻击者不会引起超过报警阈值的异常活动峰值。攻击者可以在系统内部保持隐蔽,并且能够不受干扰地进行信息收集和滥用操作。曾经发生过一起大规模的用户账户违规事件,目标是雅虎!网络门户。该事件是在隐秘模式下进行的,直到几年后,违规行为才被发现并公之于众。

相反,为了应对用户账户被攻击的策略,必须考虑可能影响用户和攻击者行为的上下文和场景变化,这就需要采用预测性异常检测方法,从对过去数据的分析出发,揭示潜在的模式,外推用户未来的行为,并及时识别潜在的攻击或欺诈尝试。

预测不可预测的事件

预测分析的任务是揭示隐藏的模式,识别数据中的潜在趋势。为此,需要结合各种数据挖掘和机器学习ML)方法,以便利用来自组织中各类异构信息源的结构化和非结构化数据集。

通过这种方式,可以将原始数据转化为可操作的预测响应,应用不同的自动化学习算法对数据进行处理。

不同的算法显然会在预测准确性方面提供不同的结果。

正如我们在前几章中看到的,当我们需要处理离散的答案(垃圾邮件或正常邮件)时,分类算法特别适用,而当我们需要连续的输出(即,具有更高粒度的输出值)时,回归算法是我们首选的选择。

类似地,管理大规模分类任务时,我们可以考虑使用线性支持向量机SVMs)和使用决策树随机森林,这些通常在我们需要对数据进行分类时提供最佳结果。

需要特别提及的是无监督学习和聚类算法,它们在探索数据中潜在和未知的模式时特别有效,能够执行诸如异常检测、可疑用户行为等任务。

选择正确的特征

采取预测方法以检测可能的用户账户违规行为,意味着选择正确的监控特征。这些特征会根据我们认为可能发生的威胁而有所不同。

在防止通过暴力破解用户凭证(用户 ID 和密码)进行攻击的情况下,监控失败的访问尝试(登录次数)及其增长速率和随时间的变化可能就足够了。其他情况下,监控的元素可能是密码更改的频率、失败的登录、密码恢复等。

更困难的是检测可能由攻击者执行的隐形攻击,这些攻击者已经获取了正确的用户密码(因为他们之前已经破坏了与用户账户相关联的电子邮件账户,从而利用密码恢复程序),或者检测到被劫持的用户会话(也称为会话劫持,它是指滥用由合法用户正常启动的会话,并被攻击者利用以实现欺诈目的),而没有明显的账户凭证泄露。

在这种情况下,监控与用户登录相关联的 IP 地址可能很有用,以验证是否有来自相距遥远的地理区域的同时访问,或者是否在短时间内频繁访问,使用的是对特定用户不常用的设备和软件。

防止虚假账户创建

用户账户的创建也是一项需要监控的活动,以防止虚假账户在我们的平台上蔓延;只需想想这些虚假账户通过混淆和欺骗合法用户,诱使他们做出可能导致欺诈或账户泄露的行为。

需要监控的事件可以追溯到假档案创建过程中通常涉及的阶段,即请求激活新账户和识别现有账户中的假档案,这些账户因用户不当行为必须被阻止或取消。

新账户异常创建的一个可能指示器(这些账户很有可能是虚假档案)是,由同一 IP 地址在短时间内(例如不到一小时内)激活大量新账户。

对于现有账户,一个可以可靠地指示假档案存在的异常指示器可能是大量用户帖子在短时间内发布,这使我们认为一个旨在在平台上传播垃圾邮件的机器人可能存在。

账户声誉评分

因此,用户账户活动的监控必须考虑到新创建和现有账户,以防止现有账户被攻击者侵入后进行恶意活动。建议将声誉度量(声誉评分)与用户的行为相关联,以此来估算。这种声誉评分还能帮助我们识别隐蔽模式下进行的攻击,从而防止攻击未被察觉。它通过利用报警系统来监控异常和嘈杂的活动峰值,达到了这一目的。

在估算与每个用户账户相关的声誉分数时,我们可以考虑各种特征:

  • 用户在一段时间内发布的帖子数量和频率

  • 通过代理、VPN 或其他 IP 匿名化系统访问用户账户

  • 使用不常见的用户代理(例如脚本)登录

  • 用户在键盘上打字的速度

这些以及其他特征可以有效地考虑用于训练我们的算法,并动态地估算个别用户的声誉分数。

分类可疑的用户活动

一旦我们积累了足够的特征来填充我们的数据集,就需要决定采取什么样的策略来训练我们的算法。特别是,自然采用的方法是监督学习,这通过利用我们已掌握的信息并利用我们之前对被认为是可疑账户的分类来实现。事实上,我们可能已经在黑名单中积累了不少用户账户,或使用基于规则的检测系统将其标记为可疑。

作为正向训练的例子,我们可以考虑与被暂停或列入黑名单的账户相关的特征,而与仍然启用的账户相关的特征则可以作为负向训练的例子。我们只需要选择最适合我们用例的监督学习算法,然后进入训练阶段,使用之前识别并与前述正向和负向示例相关联的标签进行训练。

监督学习的优缺点

无论看起来跟随监督学习策略多么合乎逻辑,都必须考虑到其中的 методологические 风险。

其中一个主要问题是,我们的算法将难以识别新的可疑活动案例,因为它们已经受到先前分类标签的影响,而这些标签可能会受到系统性错误的影响。为了重新训练我们的模型,以便检测新的可疑活动形式,我们将被迫插入不同于之前的分类规则,这些新规则应能正确检测与新样本相关联的新标签。

然而,这并不能避免放大之前在我们模型中引入的系统性错误的风险;如果我们错误地将某些用户类别列入黑名单(例如,所有从属于特定地理区域的 IP 地址连接的用户,而该地区之前被认定为垃圾邮件活动的来源),我们将向模型中引入假阳性,这将导致模型自我反馈并加剧这一问题。

为了减少这些假阳性对结果的扭曲效果,我们应该在每个后续训练阶段对提交给算法的样本进行适当的加权。

聚类的优缺点

另一种可以用来对用户账户可疑活动进行分类的方法是聚类。通过根据用户活动类型(如用户发帖频率、在平台上花费的时间、登录频率等)将用户账户分为同质化组,也可以识别出可能涉及多个被相同攻击者攻击的账户的可疑活动。例如,这些攻击者可能试图通过协调多个账户的活动,传播垃圾邮件或发布不受欢迎的帖子。

聚类实际上是一种能够发现不同用户群体之间相似性(甚至是隐藏的相似性)的方法;一旦将用户分为不同的群集,我们就需要确定哪些群集实际上代表了可疑活动,并在每个群集中,识别出哪些账户涉及可能的欺诈行为。

然而,即便在聚类的情况下,也需要仔细选择使用的算法类型:事实上,并非所有的聚类算法都能有效地检测到可疑活动。

例如,聚类算法(如 k-means)要求正确确定聚类的数量(通过预先定义参数 k 的值,该值也决定了算法的名称),这一特性在实际检测可疑用户活动时并不十分适用,因为我们通常无法准确地定义将账户分组的聚类数量。

此外,像 k-means 这样的算法不能与以类别或二进制分类值表示的特征一起使用。

用户认证通过击键识别进行

鉴于我们之前提到的限制和方法学问题,近年来,我们越来越多地采用新型的生物识别方式来检测可疑用户账户。由于神经网络的广泛应用,这些技术的使用变得比过去更加便捷。

相同的用户认证过程通常也通过生物识别技术实现,生物识别技术(如果没有取而代之的话)会补充(甚至替代)传统的基于密码的认证方式。

当我们谈论生物识别时,可以考虑一些独特的身体特征,这些特征可以可靠地且独特地追溯到特定的用户,如虹膜、面部、指纹、声音等。行为和习惯也可以通过模式来识别,这些模式通常可以可靠地与个体用户关联;在这些生物识别行为中,击键输入(也称为击键动态)就像手写一样,有助于可靠地识别不同的个体。

Coursera Signature Track

用户认证的第一个具体应用实例是 Coursera 引入的 Signature Track 技术,该技术几年前开始用于识别参与考试的学生,以确认他们在完成课程后所获得的成就证书的有效性。

ubiquity.acm.org

Signature Track 是一个过程,通过它可以将学生的课程作业与其真实身份相连接,因此,在课程结束时,学生将获得由 Coursera 和提供课程的大学共同颁发的经过验证的证书,证书上会写明他们的名字。

该证书具有唯一的验证代码,允许第三方(如雇主)验证真实候选人完成课程的情况。

Signature Track 的独特特征不仅与身份验证和身份确认程序相关,还与高规模维度相关,这得益于 Coursera 注册学生数量的不断增长;实际上,Coursera 的一门课程通常涉及 40,000 到 60,000 名学生。因此,身份验证和身份确认程序的特点是高效,不需要讲师或工作人员的干预。

此外,与其他网络服务(如在线银行或电子商务)不同,Coursera 用户账户的验证和身份认证管理变得复杂,因为用户容易将登录凭证提供给他人,以便他人代为完成作业。这一特殊性促使 Coursera 采用了两种基于人脸识别和与个体学生相关的打字模式的独立生物识别和摄影认证方法。在注册阶段,Coursera 要求学生通过网络摄像头提供一张照片,并附上身份证明文件的副本。

此外,在注册阶段,学生被要求在键盘上输入一句简短的句子,以便识别他们自己的生物识别击键资料。这是通过击键动态实现的。

击键动态

击键动态基于按键事件的节奏和韵律,这些特征对每个学生来说都是独特的;然而,由于一系列外部随机因素的影响,例如中断、错误修正或使用特殊功能键(如ShiftCaps Lock),这些事件无法直接用于机器学习算法。

因此,有必要将表示用户打字行为的原始数据转换为一组能够正确表示用户键盘动态的特征数据集,从而清除数据中的随机干扰因素。

基于击键动态的异常检测

关于使用击键动态进行异常检测的首批科学研究之一是 Kevin S. Killourhy 和 Roy A. Maxion 撰写的论文《Comparing Anomaly-Detection Algorithms for Keystroke Dynamics》。该研究的作者提出了收集击键动态数据集,以测量不同检测器性能的方法;他们收集了 51 名受试者输入 400 个密码时的数据,并提交了 14 种不同算法收集的数据,这些算法通过用户检测性能来评估。

本研究的目的是可靠地识别那些通过不同的打字模式窃取其他用户密码的冒充者。

尝试使用被盗密码进行身份验证的冒充者,将会根据与真实用户不同的击键动态特征被识别并及时阻止。

用于确定击键动态的一些特征如下:

  • Keydown-keydown:这是连续按键之间按下时间的间隔。

  • Keyup-keydown:这是按键释放与下一个按键按下之间的时间间隔。

  • Hold:这是每个按键按下和释放之间的时间间隔。

从原始数据中提取出一组时序特征,这些特征将被输入到用户检测算法中。

击键检测示例代码

www.cs.cmu.edu/~keystroke/DSL-StrongPasswordData.csv.csv
H
DDUD

击键检测脚本的代码如下:

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
%matplotlib inline

from sklearn.model_selection import train_test_split
from sklearn import metrics

from sklearn.neighbors import KNeighborsClassifier
from sklearn import svm
from sklearn.neural_network import MLPClassifier

pwd_data = pd.read_csv("https://www.cs.cmu.edu/~keystroke/DSL-StrongPasswordData.csv", header = 0)

# Average Keystroke Latency per Subject

DD = [dd for dd in pwd_data.columns if dd.startswith('DD')]
plot = pwd_data[DD]
plot['subject'] = pwd_data['subject'].values
plot = plot.groupby('subject').mean()
plot.iloc[:6].T.plot(figsize=(8, 6), title='Average Keystroke Latency per Subject')

脚本的结果可以在以下图表中看到:

脚本继续进行数据集拆分,然后应用不同的分类器,如以下示例所示:

data_train, data_test = train_test_split(pwd_data, test_size = 0.2, random_state=0)

X_train = data_train[pwd_data.columns[2:]]
y_train = data_train['subject']

X_test = data_test[pwd_data.columns[2:]]
y_test = data_test['subject']

# K-Nearest Neighbor Classifier
knc = KNeighborsClassifier()
knc.fit(X_train, y_train)

y_pred = knc.predict(X_test)

knc_accuracy = metrics.accuracy_score(y_test, y_pred)
print('K-Nearest Neighbor Classifier Accuracy:', knc_accuracy)
K-Nearest Neighbor Classifier Accuracy: 0.3730392156862745

# Support Vector Linear Classifier
svc = svm.SVC(kernel='linear') 
svc.fit(X_train, y_train)
y_pred = svc.predict(X_test)

svc_accuracy = metrics.accuracy_score(y_test, y_pred)
print('Support Vector Linear Classifier Accuracy:', svc_accuracy)
Support Vector Linear Classifier Accuracy: 0.7629901960784313

# Multi Layer Perceptron Classifier
mlpc = MLPClassifier()
mlpc.fit(X_train,y_train)

y_pred = mlpc.predict(X_test)
mlpc_accuracy = metrics.accuracy_score(y_test, y_pred)
print('Multi Layer Perceptron Classifier Accuracy:', mlpc_accuracy)
Multi Linear Perceptron Classifier Accuracy: 0.9115196078431372
多层感知器(MLP)
# Drawing confusion matrix for Multi Layer Perceptron results
from sklearn.metrics import confusion_matrix

labels = list(pwd_data['subject'].unique())
cm = confusion_matrix(y_test, y_pred, labels) 

figure = plt.figure()
axes = figure.add_subplot(111)
figure.colorbar(axes.matshow(cm))
axes.set_xticklabels([''] + labels)
axes.set_yticklabels([''] + labels)
plt.xlabel('Predicted')
plt.ylabel('True')

脚本绘制的混淆矩阵如以下图所示:

scikit-learn
KNeighborsClassifier

还展示了每个受试者的平均击键延迟的图形表示以及使用多层感知器分类器获得的结果的混淆矩阵。

使用多层感知器进行用户检测

为什么多层感知器(MLP)分类器在预测准确性方面表现出显著更好的结果?

答案在于它代表了一个人工神经网络ANN)。

人工神经网络(ANNs)构成了深度学习的基础元素,是深度学习算法所具有的高潜力的根基,允许例如对大量数据进行分类、进行人脸和语音识别,或者击败像卡斯帕罗夫这样的国际象棋世界冠军。

我们在第三章中遇到了感知器,Ham or Spam? 使用 AI 检测电子邮件网络安全威胁;我们也看到它在数据无法线性分割的分类场景中的局限性。然而,多层感知器克服了单一感知器的局限性。

实际上,MLP 由多个人工神经元层组成,每个层由感知器实现。

多层感知器(MLP)可以有三层或更多层的完全连接的人工神经元,这些神经元共同构成一个前馈网络。重要的是,MLP 可以逼近任何连续的数学函数;因此,我们可以添加任意数量的隐藏层,从而增强其整体预测能力。

面部识别的生物识别认证

除了使用键盘动态进行身份验证外,使用面部识别的身份验证方法越来越普遍。

这些过程受益于神经网络的不断扩展,以及硬件外设(如嵌入式摄像头)的普及,这些外设已预装在智能手机、平板电脑、PC 和其他设备上。

尽管乍看之下有些奇怪,使用生物识别证据的想法并不新颖,它可以追溯到不久之前的时代。虽然指纹的使用在上世纪初进入了警察操作领域,但某些基本形式的面部识别可以追溯到用于悬赏通缉犯的海报,这在西部荒野中非常常见,直到最近的侦探用的画面特征识别。

然而,毫无疑问,近年来我们见证了生物识别证据使用的真正爆发;考虑到与互联网使用以及与国家安全相关的威胁不断增加,这种趋势并非偶然,特别是在各国对抗恐怖主义的背景下。

在许多情况下,互联网使用促进了匿名性,特别是在那些网络接入控制不够系统和可靠的国家。如果通过 IP 地址或由用户名和密码组成的常见访问凭证进行的检查不够充分,就必须通过更严格的个人身份验证方式来补充。

面部识别的优缺点

在某些方面,面部识别的使用似乎是生物识别程序中首选的方式;利用智能手机和平板电脑等配备高清摄像头的设备的广泛普及,面部识别似乎是验证身份的最合乎逻辑和实用的解决方案。

然而,有一些技术方面不容忽视。

为了使面部识别成为一种可靠的身份识别方法,有必要确保所使用的图像没有受到环境因素(如反射、阴影、入射光等)的扭曲,这些因素会使得面部识别变得更加困难;面部的曝光角度在确定面部识别的可靠性方面也有其重要性。

当尝试在从人群图像中提取的面部样本上使用面部识别时,这些问题尤为明显;结果往往是,假阳性数量使得该识别方法变得无效。

因此,面部识别的有效性和可靠性,在我们能够在受控环境中使用时会更大,在这种环境下,潜在的干扰因素可以降到最低。而在我们试图在野外环境中使用它进行比较时(例如在人群中识别个体),其有效性则会较小。

我们不能忘记生物识别程序所依赖的基本假设:唯一性,即将生物识别证据专门归属于某个特定个体的可能性。在面部识别的情况下,这一假设并不总是成立。

除了明显的面部相似性案例(如长得像的人),同一个人随着时间的推移,面部也可能发生变化,原因可能是由于疾病、压力、事故或单纯的衰老引起的身体变化;此外,随着人口的增加,遇到虚假相关性的可能性也相应增加。由于这一简单的效应,为了提高识别程序的可靠性,必须考虑的数据量将随着数据集规模的增大而不成比例地增加。

所有这些因素使得可靠地训练面部识别算法变得尤其困难,从而使得面部识别的实时使用变得不太实用。

如果我们考虑到需要在存档证据与随时间积累的新图像之间进行的比较次数,我们立刻会意识到,进行全面验证,比较它们之间所有可能的组合,是不可行的。

正如指纹识别领域所发生的情况一样,我们应该将比较减少到仅仅是那些在概率上被认为可靠的、用于识别目的的特征(称为分片);(在指纹的情况下,这些特征被称为细节点,即指纹中不常见的证据区域,如两条脊线融合或脊线终止),并使用适当的相似性度量方法,如局部敏感哈希LSH)。

尽管面部识别程序在表面上看起来非常实用,但它们并非没有问题,且与它们可能产生的高假阳性率有关。

特征脸面部识别

在最常见的面部识别技术中,有一种名为特征脸的技术;正如我们将看到的,这个名字来源于其实现过程中所使用的线性代数方法。

人工智能与网络安全实用指南(二)从技术角度来看,面部识别是一个分类问题,旨在将面孔的名称与相应的图像进行结合。

我们必须区分面部识别与面部检测,后者是旨在识别图像中是否存在面孔的程序。面部识别是一个分类问题,假设已经存在一个包含面孔图像的档案,我们需要将一个面孔与一个名字进行匹配。

为此,我们必须能够比较我们档案中的图像和即将进行面部识别的新图像。

解决这个问题的直接方法可能是通过计算图像中特征之间的互反差异,将图像降维为多个特征向量。然而,正如我们之前提到的,鉴于需要在接近实时的情况下进行大量比较,这种方法将是不切实际的。

就其本质而言,图像具有较高的维度(即不同特征),这些维度可能包含许多与识别无关的无关信息(构成白噪声)。为了进行可靠的比较,我们需要将维度数目减少到与识别目的密切相关的那些维度。

因此,利用特征脸的面部识别技术基于一种无监督的降维算法,称为主成分分析PCA),这并非巧合。

使用主成分分析(PCA)进行降维

PCA 可以识别数据集的代表性变量(也称为主成分),并选择数据分布较为分散的那些维度。

为了理解为什么我们需要对高维数据(如图像)进行降维,以及如何通过 PCA 实现降维,我们可以考虑以下描述性示例。

假设我们需要区分食物的营养价值;我们应该考虑哪种营养成分?例如维生素、蛋白质、脂肪和碳水化合物?

为了回答这个问题,我们必须能够确定哪个营养成分作为主成分,也就是说,我们应该考虑哪种营养成分(或营养成分的组合)作为各种食物的特征元素?

问题在于,并非所有食物都含有相同的营养成分(例如,维生素在蔬菜中含量较多,而在肉类中则较少)。因此,我们可以将一组不同的营养成分视为主成分,例如通过将脂肪(肉类中存在的营养成分)加入到蔬菜中的维生素(含量较多)中。

然后,我们将添加(或删除)营养素,以识别可以作为主成分的最佳元素组合,也就是说,沿着这个成分,数据的分布最为广泛。

我们还必须考虑到某些营养素可能高度相关,这意味着它们沿相同方向变化,而其他营养素则沿相反方向变化(例如,随着维生素的增加,脂肪水平降低;为了衡量相关性程度,我们可以使用线性相关系数 R)。

如果我们能识别出具有高相关性的元素,就可以减少在定义主成分时考虑的变量数量;这正是 PCA 的目的:实现维度减少(减少描述给定数据集的维度数)。

主成分分析

从形式上讲,PCA 由选择一个空间的超平面组成,该超平面是数据(在空间中由点表示)主要分布的方向;这在数学上转化为寻找方差最大值所在的轴。

以下截图展示了一个数据集的主成分:

为了识别这个轴,我们需要计算与我们的数据相关的协方差矩阵,识别矩阵中最大的特征向量,这些特征向量对应于主成分相关的轴。通过这样做,我们可以减少数据的维度。

特征向量(以及与之相关的特征值)这一概念来源于线性代数,并为基于特征脸的人脸识别技术命名。

接下来,我们将简要分析这些概念,并展示它们的数学形式化。

方差、协方差和协方差矩阵

要理解特征向量和特征值的概念,我们必须首先回顾以下一些数学定义:

  • 方差:这衡量数据内部的离散程度,表示为数据与其平均值之间偏差的平均值,如下所示:
  • 协方差:这衡量两个变量之间的线性相关程度;其数学表示如下:
  • 协方差矩阵:这是一个包含每对数据之间计算出的协方差的矩阵,这些数据来自一个数据集。
print(np.cov(X).T)
import numpy as np

X = np.array([
 [3, 0.1, -2.4],
 [3.1, 0.3, -2.6],
 [3.4, 0.2, -1.9],
])

print(np.cov(X).T)

特征向量和特征值

现在我们可以介绍特征向量和特征值的概念,它们来自线性代数。

方阵A的特征向量表示为满足以下条件的向量v

同样地,值λ(由一个标量表示)构成了向量v的对应特征值。

需要牢记的是,特征向量(及其对应的特征值)只能为方阵计算,而并非所有方阵都有特征向量和特征值。

要理解特征向量和特征值对主成分分析(PCA)的相关性,我们必须记住,向量(如特征向量)表示线性空间中的一个有向元素(具有方向性),而标量(如特征值)表示强度的度量(没有方向性)。

因此,之前显示的方程式表示的是线性变换;将特征向量v与矩阵A相乘并不会改变v的方向(它保持不变),只是改变其强度,这个强度由特征值λ的值来决定;在实践中,就好像我们在重新缩放v向量。

下图展示了由于特征值乘法引起的向量的重新缩放:

因此,为了识别协方差矩阵中的主成分,我们需要寻找对应于较大特征值的特征向量。在这种情况下,我们可以使用 NumPy 库来执行我们的计算。

假设我们有以下方阵A

特征向量和特征值(如果存在)的计算可以归结为以下 NumPy 指令:

import numpy as np
eigenvalues, eigenvectors = np.linalg.eig(np.array([[2, -4], [4, -6]]))

特征脸示例

所以,在这里我们来到了 PCA 技术在面部识别中的应用。接下来的示例中,我们将把我们档案中的每一张图像与图像中代表的人的名字关联起来。

为了实现这一点,我们需要将图像的维度(由多个特征组成,代表像素的不同特性)降至主要成分,即与识别目的最相关的特征。这些主要成分就是特征脸(Eigenfaces)。

以下屏幕截图显示了几个特征脸:

因此,我们数据集中每一张图像都可以解释为这些特征脸的组合。

vis-www.cs.umass.edu/lfw/lfw-funneled.tgz.

在这个例子中,与前一个键盘动态的例子一样,我们将使用 MPL 分类器进行图像分类。

classification_report()
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import PCA
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

lfw = fetch_lfw_people(min_faces_per_person=150)

X_data = lfw.data
y_target = lfw.target
names = lfw.target_names

X_train, X_test, y_train, y_test = train_test_split(X_data, y_target, test_size=0.3)

pca = PCA(n_components=150, whiten=True)
pca.fit(X_train)

pca_train = pca.transform(X_train)
pca_test = pca.transform(X_test)

mlpc = MLPClassifier()
mlpc.fit(pca_train, y_train)

y_pred = mlpc.predict(pca_test)
print(classification_report(y_test, y_pred, target_names=names))

执行前述脚本后返回的输出如下:


                precision    recall  f1-score   support

  Colin Powell       0.92      0.89      0.90        79
 George W Bush       0.94      0.96      0.95       151

     micro avg       0.93      0.93      0.93       230
     macro avg       0.93      0.92      0.93       230
  weighted avg       0.93      0.93      0.93       230

总结

本章展示了可以用来提高用户认证程序的有效性并及时检测可能存在的受损用户账户的不同技术。

这些技术基于生物识别证据的使用,如面部识别,或生物行为识别,如键盘动态,这些都可以通过使用神经网络等 AI 算法来实现,如 MLP。

我们还看到如何通过使用 PCA 将数据的维度减少到其主要成分。

最后,强调了使用生物识别证据进行用户认证和识别的优缺点。

在下一章中,我们将学习如何使用云端 AI 解决方案进行欺诈防范。

第八章:使用云 AI 解决方案进行欺诈预防

许多公司遭遇的安全攻击和数据泄露的目标是违反敏感信息,如客户的信用卡详细信息。这类攻击通常以隐蔽模式进行,因此,使用传统方法难以检测到这些威胁。此外,需要监控的数据量往往庞大,单靠传统的提取、转换和加载ETL)程序,运行在关系型数据库上,无法有效分析数据,因此采用人工智能AI)可扩展解决方案显得尤为重要。通过这样做,企业可以利用云架构来管理大数据,并运用预测分析方法。

信用卡欺诈代表了人工智能(AI)解决方案在网络安全领域应用的一个重要考验,因为它要求开发利用大数据分析的预测分析模型,并通过使用云计算平台进行处理。

在本章中,您将学习以下内容:

  • 如何利用机器学习ML)算法进行欺诈检测

  • 如何通过集成(bagging)和提升(boosting)技术提高算法的效果

  • 如何使用 IBM Watson 和 Jupyter Notebook 分析数据

  • 如何利用统计度量进行结果评估

让我们来介绍一下算法在信用卡欺诈检测中所扮演的角色。

引入欺诈检测算法

近年来,我们见证了金融领域欺诈活动的增加,特别是在信用卡欺诈方面。这是因为网络犯罪分子设立信用卡欺诈活动相对容易,因此,金融机构和组织必须能够及时识别欺诈行为。

此外,在信用卡欺诈的背景下,欺诈检测与预防的工作还受到一个复杂因素的影响:这种类型的欺诈具有全球化的特点;也就是说,它涉及不同的地理区域以及多种金融机构和组织。

因此,能够共享全球不同组织之间的可用信息源至关重要。

这些信息源是异构的,且具有数据生成爆炸性增长的特点,必须实时分析。

这类似于典型的大数据分析场景,要求使用分析工具及合适的软件和硬件平台,例如云计算所提供的工具。

这种情境的复杂性还由于我们比以往任何时候都更容易发现洗钱和非法活动,如国际恐怖主义融资,通常与信用卡欺诈相关联。

网络犯罪分子进行的非法活动因此具有跨国性质,涉及不同领域的有组织犯罪。

所有组织,无论是公共部门还是私人部门,都被要求在反洗钱等法规的基础上合作,共同打击这些非法活动。

网络犯罪分子对信用卡欺诈的兴趣日益增长,源于扭曲的经济激励;信用卡欺诈的预期回报远高于其他非法活动,且被警方抓获的风险远低于传统犯罪。

此外,如果个人金融欺诈涉及的金额和价值没有超过某些阈值,金融机构本身也不愿追究非法活动,因为调查活动可能会被证明是经济上不划算的(例如,通过位于不同国家和地区的假冒电子商务网站进行的欺诈,往往需要涉及不同法律管辖区的调查活动,从而增加执法成本和实施时间)。

信用卡欺诈导致的金融损失并不是金融机构必须面对的唯一问题;由于失去信誉和可靠性,还会造成声誉损害。

此外,信用卡欺诈还可能对客户构成威胁;信用卡欺诈的一个令人不安的方面与身份盗窃现象的日益增多有关,身份盗窃可以通过伪造文件或通过获取身份文件的数字副本(例如,通过数据泄露、网络钓鱼邮件等方式)轻松实现。

处理信用卡欺诈

然而,根据前述讨论,金融机构随着时间的推移引入了防止欺诈的措施:实际上,金融机构已经推出了基于双重身份验证的安全措施,通过将一次性密码(OTP)代码通过短信发送到客户的手机号码,从而整合传统的身份验证程序,以防止支付工具的滥用。

然而,事实仍然是,这些措施还不够,金融机构因信用卡欺诈而遭受的货币损失仍然高达数十亿美元;因此,减少这些损失的最有效预防活动是基于欺诈检测和预防的程序。

与信用卡欺诈检测和预防相关的分析领域相当复杂,这将使我们有机会在实践中看到,使用预测分析、机器学习和大数据分析技术的不同分析方法。

本章中,我们将探讨使用云计算平台的优势(使用 IBM Watson 平台提供的工具),考虑到欺诈检测与防范需要集成不同的活动分析,以及集成异构数据源。

这将引导我们采用一种利用预测分析的检测方法,包括认知计算等创新方法。

用于欺诈检测的机器学习

dalpozz.github.io/static/pdf/Dalpozzolo2015PhD.pdf

信用卡欺诈检测的算法选择和设计具有以下特点:

  • 有关欺诈交易的数据通常不易获得,因为金融机构不愿公开此类信息,以避免声誉损害以及保密合规要求。

  • 从技术角度来看,欺诈数据通常表现为非平稳分布,也就是说,它们随时间发生变化;这也与客户消费行为的变化有关。

  • 交易分布严重失衡,因为欺诈通常仅占总体交易的一个小比例;因此,分布显示出向真实交易的高度偏斜。事实上,我们通常只能衡量已被检测到的欺诈,而要估计未被检测到的欺诈实例(假阴性)则要困难得多。此外,欺诈通常是在事件发生后很长时间才被记录的。

由于欺诈交易的内在特征,这些误表示导致了在选择和设计检测与预防算法时所面临的挑战,例如:

  • 在数据分析中使用采样策略;在存在不平衡分布的情况下,选择欠采样/过采样策略可能更加有用。

  • 整合人工操作员在识别欺诈警报时生成的反馈。这一方面对于在非平稳数据存在的情况下改善算法学习过程尤为重要,而这些数据随着时间的推移不断变化。

所有这些都转化为一个欺诈检测与防范系统的开发,该系统能够集成大数据分析、机器学习算法以及人工操作员的反馈。因此,显而易见,使用云计算架构是必然的实施选择。

欺诈检测与防范系统

有多种可能的信用卡欺诈场景,包括以下几种:

  • 信用卡盗窃:这是实践中最常见的情况;犯罪分子盗窃信用卡并在短时间内尽可能多地消费。这种活动通常会很喧闹,可以通过与合法信用卡持有人的消费习惯进行比对,借助异常或不寻常的模式检测来识别。

  • 信用卡滥用:与前述情况不同,欺诈者不需要实际持有信用卡,只需知道与卡片相关的相关信息(如识别码、PIN 码、个人身份号码、卡号、设备代码等)即可。这是最隐蔽的欺诈场景之一,因为它是以悄无声息的方式进行的(与前述场景相比,它不那么显眼),而信用卡的合法拥有者通常并未意识到背后正在进行的欺诈活动。

  • 身份盗窃:在这种情况下,信用卡是基于虚假的个人信息发放的,或者通过利用毫无防备的第三方的个人信息,这些第三方发现自己在名下被收取服务费用以及进行的取款和支付。

我们应该牢记,欺诈场景随着时间的推移而发展,特别是在涉及金融服务和技术的流程和产品创新方面,这些技术被金融机构采纳。

同样,欺诈者根据信用卡发卡机构为防止和打击欺诈所采取的技术措施调整自己的行为。

要正确实施欺诈检测与防范系统FDPS),必须区分与信用卡欺诈管理相关的两项活动:

  • 欺诈检测:这是旨在正确和可靠地识别欺诈案件的一套程序;它是在欺诈发生后实施的。

  • 欺诈防范:这是旨在有效预防欺诈发生的一套程序;它是在欺诈发生之前实施的。

这两项活动的特点在于实施的程序类型不同,以及它们引入的时机也有所不同,具体如下:

  • 在欺诈预防的情况下,分析程序可以利用由领域专家处理的基于规则的警报系统(因此,需要操作员不断微调),或利用基于数据挖掘、机器学习、神经网络等的先进分析技术,通过这些技术可以自动发现数据分布中的模式。

  • 在欺诈检测的情况下,分析程序旨在根据现有数据正确分类欺诈,从而将其与真实交易区分开来。

实施 FDPS 的一个重要方面不仅是其能够实现的结果的可靠性,还包括其成本效益。如果实施成本高于由于欺诈造成的损失,那么采用 FDPS 就毫无意义!

这两项活动之间存在明显的权衡;如果无法防止欺诈尝试,那么必须尽可能快地检测到它。

同样,这两项活动都需要尽量减少假阳性(即那些被错误地视为欺诈的交易,实际上它们是合法的交易)数量,并避免由于假阳性引发的自动反应导致客户可能遭受的服务拒绝(例如,尽管交易是合法的,信用卡仍被自动封锁)。

管理假阳性的问题还包括人工操作员进行检查的可扩展性差;如果人工操作员执行的控制通常在正确识别真正的欺诈中起到决定性作用,那么对所有交易进行系统性的人力控制,实际上就是过度的。

这就是为什么正确实施自动化检测和预防程序来支持操作员分析变得至关重要。

在本章中,我们将探讨如何考虑管理大量数据所涉及的困难,这些数据往往是不平衡的,并且由于客户不断变化的购买习惯而持续变化,这与现有算法的关系。

在接下来的章节中,我们将研究在实施自动化预测模型时可以采用的可能策略,分析专家驱动策略与数据驱动策略之间的差异。

专家驱动的预测模型

专家驱动的方法包括基于由行业专家(而非偶然的)制定的规则来实施预测模型,因此专家驱动的方法也被定义为基于规则的方法。

if...then...else

因此,一个可能的规则是:如果信用卡交易金额超过某一特定金额,并且与某一特定的日常频率相关(与客户购买习惯的历史系列进行比较),则将所有交易视为欺诈性交易,规则可能如下:

IF amount > $1,000 AND buying_frequency > historical_buying_frequency THEN fraud_likelihood = 90%

对于在地理位置上相距很远的后续交易,可能会呈现如下情况:

IF distance(new_transaction, last_transaction) > 1000 km AND time_range < 30 min THEN block_transaction

在第一种情况下,我们将看一个评分规则的例子,而在第二种情况下,我们将讨论一个阻止规则。

评分规则旨在根据常见经验规则估算与交易相关的欺诈概率,并通过在超过特定阈值后对事件进行分类,来实现这一目标。

阻止规则更加严格,因为它们不仅仅限于估算欺诈的概率。相反,它们旨在在交易完成之前拒绝交易的授权;因此,阻止规则必须基于更严格的逻辑条件(例如在我们的例子中,如果交易与前一次交易相隔不足半小时,并且执行地点之间的距离大于 1000 公里,则拒绝该交易。合理推测,同一客户在这么短的时间内不可能在如此远的地方之间移动)。

基于规则的预测模型的优点如下:

  • 警报实施的易用性

  • 警报理解的易用性

  • 更高的警报可解释性

专家驱动的预测模型的缺点同样显而易见:

  • 它们表达了主观判断,可能会因执行这些模型的专家不同而有所差异。

  • 它们只能处理少数几个重要变量及其相互关系。

  • 它们基于过去的经验,无法自动识别新的欺诈模式。

  • 需要专家不断地手动微调规则,以便考虑到欺诈者所采用的欺诈策略的演变。

因此,这些缺点有利于推动数据驱动预测模型的采用。

数据驱动预测模型

数据驱动预测模型利用自动化学习算法,试图根据数据驱动的学习方法调整其预测,持续更新检测和预防程序,并基于动态识别的行为模式进行操作。

数据驱动预测模型中使用的算法源自多个定量分析领域,从统计学到数据挖掘和机器学习,旨在学习数据中隐藏或潜在的模式。

在数据驱动预测模型的实现中,机器学习算法的特权角色一目了然;机器学习使得基于对数据进行训练所获得的模型,能够识别出预测模型。

此外,在欺诈检测领域使用机器学习有几个优点:

  • 分析多维数据集的能力(数据集特征数量较多,代表欺诈的可能解释变量)

  • 关联各个识别特征之间的能力

  • 动态更新模型、使其适应欺诈者所采用策略变化的能力

  • 机器学习采用数据驱动的方法,实时利用大量数据(大数据)

鉴于此,数据驱动的预测模型通常比基于规则的模型更具鲁棒性和可扩展性。

然而,与基于规则的模型不同,数据驱动预测模型往往表现得像“黑箱”,这意味着它们生成的警报很难解释和证明(例如,在客户的交易被基于算法自动决策拒绝后,客户提出澄清要求时)。

同样,数据的特性本身可能会导致算法正确实现时的困难;以信用卡为例,交易分布存在重要的不规则性,如不平衡、非平稳和偏斜。因此,必须仔细选择能够充分处理这些不规则性的机器学习算法。

特别是在非平稳数据的情况下(即数据随着客户购买行为的变化而随时间变化),算法必须仔细更新自身的学习参数,权重最近的数据,或忽略过时的样本。

数据驱动预测模型的一个无可争议的优点是能够将操作员的反馈集成到预测中,从而提高程序的准确性。

操作员的反馈,事实上,具有更高的可靠性,能正确分类欺诈案件,从而减少假阴性的数量(即可能未被发现的欺诈行为),并可以自动集成到数据驱动的预测模型中。

相反,基于规则的模型需要手动修订,以考虑操作员的反馈。

结合专家驱动和数据驱动预测模型的优势构成了 FDPS 的核心优势,正如我们接下来将看到的那样。

FDPS – 集两者之长

因此,专家驱动和数据驱动预测模型可以在 FDPS 中结合使用,以利用两种方法的优势,通过减少假阴性和假阳性来提高预测的准确性。

基于规则的模型通常会减少假阴性的数量,尽管这会增加假阳性的数量;与数据驱动模型结合使用时,可以通过减少假阳性来改善预测。

此外,正如我们所看到的,数据驱动的模型允许将操作员的反馈与其他大数据源集成,从而有助于动态更新 FDPS。

FDPS 的自动化维护和调优活动需要实施能够自主学习新预测模式的机器学习算法,这些模式从大量数据中开始。

如前所述,信用卡交易的统计分布具有非平稳数据的特点(数据的特征随着消费习惯的变化而变化),而且数据通常偏向于代表合法交易的大类,而不是代表欺诈行为的小类。

这是因为欺诈案件的数量相对于总交易数是极少的(此外,欺诈交易的检测通常需要更长时间,因此欺诈交易的类别通常较小)。

并非所有的机器学习算法都能有效处理同时具备非平稳和不平衡特征的数据。因此,需要适当选择算法,以获得可靠和准确的预测。

从不平衡和非平稳数据中学习

在第一章《面向网络安全专业人士的 AI 简介》中,我们看到了机器学习算法如何分为监督学习和无监督学习;这一划分在信用卡欺诈检测中同样有效,尽管必须注意启发这两类算法的不同假设。这是因为它们对预测的可靠性和准确性有重要影响。

在监督学习算法的情况下,假设有一个已经分类的数据集(有标签样本);也就是说,每个样本之前已与两种可能类别之一(合法或欺诈)关联。

因此,监督算法是基于这些信息进行训练的,它们所做的预测是由在训练样本上进行的先前分类所决定的,这可能导致假阴性的增加。

无监督算法则不依赖于任何关于样本数据(无标签样本)可能分类的先前信息,因此必须独立推断数据可能属于的类,以便更容易地产生假阳性。

处理不平衡数据集

在信用卡交易的情况下,我们说过数据分布既是不平衡的,又是非平稳的。

解决不平衡数据分布问题的方法是在进行算法训练之前对类别进行重新平衡。

常用于重平衡样本类别的策略包括对数据集进行欠采样和过采样。

本质上,欠采样包括随机删除属于某一类别的一些观察结果,以减少其相对一致性。

在不平衡分布的情况下,例如与信用卡交易相关的分布,如果我们排除主要类别(代表合法交易)的随机样本,我们可以合理地期望数据的分布由于数据的移除不会发生根本性改变(可以可靠地视为冗余)。

然而,我们总是面临着消除包含相关信息的数据的风险。因此,确定正确的采样水平并不总是即时的,因为它取决于数据集的具体特征,因此需要使用适应性策略。

另一种数据采样策略包括过采样,即通过在较小类别中生成合成样本来增加其大小。

与过采样技术相关的缺点包括引入过拟合的风险,以及增加模型的训练时间。

处理非平稳数据集

为了管理分布的非平稳特性,过于强调由人工操作员获得的反馈可能是有用的,这有助于改善受监督样本的分类。

因此,在存在非平稳数据的情况下,使用一组分类器(集成学习)可能是有用的,其训练是在不同的样本上进行的,以提高整体预测准确性。

通过集成不同的分类器,可以将基于新观察到的知识与先前获得的知识结合起来,根据其分类能力对每个分类器进行加权,排除那些不再能够表示数据分布随时间变化的分类器。

信用卡欺诈检测的预测分析

要充分解决欺诈检测问题,必须开发预测分析模型,即能够使用数据驱动方法识别数据中趋势的数学模型。

不同于描述性分析(其范式由商业智能BI)构成),后者仅限于根据应用描述性统计产生的度量对过去数据进行分类(例如总和、平均值、方差等),准确描述正在分析的数据特征;相反,通过查看现在和过去的情况,预测分析试图以一定的概率预测未来事件。它通过挖掘分析数据中的隐藏模式来实现这一点。

作为数据驱动的预测分析,利用数据挖掘和机器学习技术进行预测,且基于对大量可用数据(大数据分析)的分析。

在接下来的章节中,我们将探索如何开发用于信用卡欺诈分析的预测分析模型。我们将学习以下内容:

  • 利用大数据分析整合来自不同来源的信息

  • 结合不同的分类器(集成学习)以提高预测性能

  • 使用 bagging 和 boosting 算法来开发预测模型

  • 使用采样技术对数据集进行重平衡,从而提高预测准确性

让我们从利用大数据分析开发预测模型来管理信用卡欺诈检测的优势开始了解。

在欺诈检测中采用大数据分析

组织普遍采用的传统 ETL 解决方案,这些方案基于关系型数据库和数据仓库的数据架构,毫无疑问能够执行基于描述性分析的报告(例如商业智能报告),但无法通过数据驱动方法处理大量数据,而这种方法是预测分析的典型特征。

因此,有必要采用数据架构,通过使用功能编程范式(如 MapReduce、NoSQL 原语等)来实现处理的可扩展性。

可以利用大数据分析技术,并将其与机器学习和数据挖掘算法结合,以实现欺诈检测的自动化。

采用大数据分析范式有助于组织最大化利用其信息资产,这些资产通常来自不同(且往往异构)的数据源。这使得能够实施先进的情境意识形式,进而实时调整检测程序以适应情境变化。

众所周知,非法活动往往是相互关联的,能够构建一个整体的欺诈活动图景前提是要不断监控不同的信息源。

采用云计算平台可以促进数据的实时监控和分析,这也使得聚合各种数据源成为可能。

比如,想象一下将组织内部产生的数据和信息与公开可用的网络数据、社交媒体及其他平台的数据进行整合。通过整合这些不同的信息源,可以重构待监控的金融交易的情境(例如,通过社交媒体,你可能发现持卡人当前位于一个远离正在进行信用卡交易地点的地理位置)。

同样地,不同数据源的整合可以增强数据集特征;也就是说,从数据集中现有的变量出发,引入新的变量,这些变量可以描述合法持卡人的行为,并将其与欺诈者的行为进行比较。

例如,我们可以向现有变量中添加新的变量,这些变量包含重新计算的值,比如上一时间段的平均支出水平、每天的购买次数,以及通常在哪些商店(包括电商网站)进行购买。

通过这种方式,可以不断更新客户档案,及时发现潜在的行为异常和巩固的消费习惯。

集成学习

从数据到算法的过渡,前面我们提到过,在非平稳数据的情况下,引入分类器集成可能比单独使用个别分类器更有助于提高整体预测准确性。

因此,集成学习的目的是将不同的分类算法结合起来,从而获得一个分类器,能够提供比单个分类器更好的预测结果。

为了理解为什么集成分类器表现得比单个分类器更好,我们需要想象我们有若干个二元分类器,它们都是相同类型,具有在 75%的情况下做出正确预测,而在剩余 25%的情况下做出错误预测的能力。

通过使用组合分析和二项分布(因为我们考虑的是二元分类器),可以证明,使用集成分类器而非单个分类器时,获得正确预测的概率会提高(而错误的概率则会降低)。

例如,如果我们有 11 个二元分类器进行集成学习,那么错误率将降低到 3.4%(相比于单个分类器的 25%错误率)。

如需正式证明,请参考 Sebastian Raschka 的《Python 机器学习(第二版)》,由 Packt 出版。

你可以使用多种方法来结合分类器;其中一种方法是使用多数投票法(也称为多数投票原则)。

多数投票原则是指,在单个分类器做出的预测中,我们选择那个显示最高频率的预测。

用正式的术语来说,这就转化为计算位置统计量之一,称为众数,即频率最高的类别。

假设我们有 n 个分类器,C*[i]**(x)*,需要确定最被投票通过的预测 y,即大多数单个分类器确认的预测。我们可以写出以下公式:

显然,我们可以在可用的不同类型的算法中选择个别分类器(如决策树、随机森林、支持向量机SVMs)等)。

同时,也有几种方法可以创建集成分类器,如下所示:

  • 袋装法(Bootstrap Aggregating)

  • 提升法

  • 堆叠法

使用袋装法,可以通过选择不同的训练集并应用自助重采样技术来减少个体估计器的方差。

通过提升法,我们可以创建一个集成估计器,从而减少个体分类器的偏差。最后,通过堆叠法,将通过异构估计器获得的不同预测结果结合起来。

我们将在接下来的章节中分析创建集成估计器的不同方法。

袋装法(Bootstrap Aggregating)

自助法(bootstrap)是指对数据集进行有放回抽样的操作。因此,袋装法将每个自助样本与一个单独的估计器相关联;集成估计器通过对个别分类器应用多数投票法来实现。

要考虑的自助抽样次数可以预先确定,也可以通过使用验证数据集进行调整。

袋装法特别适用于在有放回抽样帮助下重新平衡原始数据集的情况,从而减少总方差。

提升算法

提升法则是使用从数据中提取的加权样本,这些样本的权重根据个别分类器报告的分类错误进行迭代调整,从而减少其偏差。

更重要(加权)的是对那些最难分类的观测值。

最著名的提升算法之一是自适应提升AdaBoost),其中第一个分类器在训练集上进行训练。

对于第一个分类器错误分类的样本,相关的权重会增加,然后在包含更新权重的数据集上训练第二个分类器,依此类推。迭代过程在达到预定的估计器数量时结束,或者当找到最佳预测器时结束。

AdaBoost 的主要缺点之一是该算法由于其顺序学习策略,无法并行执行。

堆叠法

堆叠法得名于集成估计器的构建方式,它是通过叠加两层来实现的,第一层由单个估计器组成,这些估计器的预测结果被传递到下层,在那里另一个估计器负责对接收到的预测进行分类。

与袋装法(bagging)和提升法(boosting)不同,堆叠法(stacking)可以使用不同类型的基础估计器,这些估计器的预测可以通过与之前不同的算法进行分类。

让我们来看看一些集成估计器的例子。

Bagging 示例

scikit-learnBaggingClassifierDecisionTreeClassifiern_estimatorsDecisionTreeClassifier
BaggingClassifierfit()predict()
max_samplesbootstrapTrue
from sklearn.tree import DecisionTreeClassifier

from sklearn.ensemble import BaggingClassifier

bagging = BaggingClassifier(
            DecisionTreeClassifier(), 
            n_estimators=300,
            max_samples=100, 
            bootstrap=True
          )

使用 AdaBoost 提升方法

scikit-learnAdaBoostClassifierDecisionTreeClassifiern_estimators
from sklearn.tree import DecisionTreeClassifier

from sklearn.ensemble import AdaBoostClassifier

adaboost = AdaBoostClassifier(
              DecisionTreeClassifier(),
              n_estimators=300
           )

另一种广泛使用的提升算法是 梯度提升 算法。为了理解梯度提升算法的特性,我们必须首先引入梯度的概念。

引入梯度

在数学上,梯度表示在给定点计算的偏导数;它还表示被考虑点的切线(斜率)。

梯度在机器学习中作为一种成本函数被用来最小化,以减少算法产生的预测误差。它的核心是最小化算法估计值与观察值之间的差异。

使用的最小化方法被称为梯度下降,它是一种优化分配给输入数据的权重组合的方法,以便获得估计值与观察值之间的最小差异。

因此,梯度下降法计算各个权重的偏导数,基于这些偏导数更新权重,直到达到对应于所求最小值的偏导数的驻点值。

梯度下降公式及其图形表示如下图所示:

问题在于,梯度下降法返回的最小值可能对应一个全局最小值(即,无法再进一步最小化),但更有可能对应局部最小值;问题在于,梯度下降法无法确定是否已经到达局部最小值,因为优化过程在达到稳定值时停止。

梯度下降优化方法如图所示:

现在让我们看看梯度提升算法的特点。

梯度提升

类似于 AdaBoost 算法,梯度提升也在每一轮迭代中基于估计器返回的值来修正估计器;在梯度提升的情况下,修正是基于前一轮估计器生成的残差误差,而不是要分配的权重(如在 AdaBoost 中)。

scikit-learnGradientBoostingClassifier
max_depth
learning_ratewarm_start
learning_rate低n_estimators
learning_raten_estimatorswarm_start=True
from sklearn.ensemble import GradientBoostingClassifier

gradient_boost = GradientBoostingClassifier(
                   max_depth=2, 
                   n_estimators=100, 
                   learning_rate=1.0,
                   warm_start=True
                 )

极限梯度提升(XGBoost)

与梯度提升相似的算法是 XGBoost 算法。

它是梯度提升的扩展,证明在处理大规模数据时更加适用,因为它具有更好的可扩展性。

XGBoost 同样使用梯度下降法来最小化估计器的残差误差,并且特别适合并行计算(这一特点使其更适合云计算)。

我们将在稍后使用 IBM Watson 在 IBM Cloud 平台上实施信用卡欺诈检测时看到 XGBoost 算法的应用。

不平衡数据集的采样方法

在进入欺诈检测操作阶段之前,最后一个需要考虑的方面是数据不平衡的管理。

我们已经说过,信用卡交易的一个特征是其向真实交易分布的失衡。

为了管理数据中的这种不对称性,我们可以使用不同的采样方法来重新平衡交易数据集,从而使分类器的性能得到提升。

最常用的两种采样模式是欠采样和过采样。通过欠采样,从最多的类别(在我们这里是合法交易类别)中随机移除一些样本;通过过采样,向最少的类别添加合成样本。

使用 SMOTE 进行过采样

在过采样方法中,我们有合成少数类过采样技术 (SMOTE);它通过插值生成合成样本,这些样本基于被过采样类别内的现有值。

实际上,合成样本是基于类中观察值周围识别到的聚类生成的,因此计算k-最近邻 (k-NNs)。

根据需要重新平衡类别的合成样本数量,随机选择一定数量的 k-NN 聚类,围绕这些聚类通过插值生成落在选定聚类中的值的合成示例。

采样示例

以下示例取自官方 Python 库 imbalanced-learn 文档,该库实现了包括欠采样和过采样算法等多种方法。

RandomUnderSampler
# From the Imbalanced-Learn library documentation:
# https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.under_sampling.RandomUnderSampler.html

from collections import Counter
from sklearn.datasets import make_classification
from imblearn.under_sampling import RandomUnderSampler 

X, y = make_classification(n_classes=2, class_sep=2,
 weights=[0.1, 0.9], n_informative=3, n_redundant=1, flip_y=0,
n_features=20, n_clusters_per_class=1, n_samples=1000, random_state=10)
print('Original dataset shape %s' % Counter(y))

rus = RandomUnderSampler(random_state=42)
X_res, y_res = rus.fit_resample(X, y)
print('Resampled dataset shape %s' % Counter(y_res))

这是一个使用 SMOTE 类的过采样技术示例:

# From the Imbalanced-Learn library documentation:
# https://imbalanced-learn.readthedocs.io/en/stable/generated/imblearn.over_sampling.SMOTE.html

from collections import Counter
from sklearn.datasets import make_classification
from imblearn.over_sampling import SMOTE 

X, y = make_classification(n_classes=2, class_sep=2,
   weights=[0.1, 0.9], n_informative=3, n_redundant=1, flip_y=0,
   n_features=20, n_clusters_per_class=1, n_samples=1000,    
   random_state=10)

print('Original dataset shape %s' % Counter(y))
Original dataset shape Counter({1: 900, 0: 100})

sm = SMOTE(random_state=42)
X_res, y_res = sm.fit_resample(X, y)
print('Resampled dataset shape %s' % Counter(y_res))
Resampled dataset shape Counter({0: 900, 1: 900})

了解 IBM Watson Cloud 解决方案

现在是时候了解市场上最有趣的基于云的解决方案之一,它将让我们看到信用卡欺诈检测实际应用的具体示例:我们所说的是 IBM Watson Cloud 解决方案,它在其他创新概念中引入了认知计算。

通过认知计算,有可能模拟典型的人类模式识别能力,从而为决策提供充分的上下文感知。

IBM Watson 可以成功应用于多个现实场景;以下是几个示例:

  • 增强现实

  • 犯罪预防

  • 客户支持

  • 面部识别

  • 欺诈预防

  • 医疗保健和医学诊断

  • 物联网 (IoT)

  • 语言翻译和自然语言处理 (NLP)

  • 恶意软件检测

在详细了解 IBM Watson Cloud 平台之前,让我们先看看与云计算和认知计算相关的优势。

云计算优势

随着更高带宽网络的普及,再加上低成本计算机和存储设备的可用性,云计算的架构模型迅速普及,得益于虚拟化解决方案的可用,无论是在软件还是硬件方面。

云计算的核心特点是架构的可扩展性,这也是其商业成功的决定性因素。

采用云计算解决方案的组织成功优化了 IT 领域的投资,从而提高了利润率;这些组织不再需要基于最坏情况(即考虑到工作负载高峰,即使只是暂时的)来规划其技术基础设施,而是通过云解决方案的按需模式,从而降低了固定成本,将其转化为可变成本。

技术投资质量的提升使得组织能够专注于管理和分析构成公司信息资产的数据。

实际上,云计算使得高效存储和管理大量数据成为可能,保证了高性能、高可用性和低延迟;为了提供这些访问和性能保障,数据存储并复制在分布在不同地理区域的服务器上。此外,通过对数据进行分区,可以获得与架构可扩展性相关的优势。

更具体来说,可扩展性与通过增加资源到架构中来管理日益增长的工作负载相关——成本以线性方式增加,且与增加的资源数量成正比。

实现数据可扩展性

传统架构(基于关系数据库和数据仓库)面临的主要问题之一是,这些解决方案在应对数据爆炸性增长时无法良好扩展。此类架构即使在设计阶段,也需要适当的规模规划。

随着大数据分析的普及,因此有必要转向其他数据存储范式,称为分布式存储系统,这些系统能够精确防止数据管理和存储中的瓶颈。

云计算广泛使用这些分布式存储系统来实现对大量数据的分析(大数据分析),即使是在流媒体模式下。

分布式存储系统由非关系型数据库组成,称为 NoSQL 数据库,数据以键值对的形式存储。这使得可以在多个服务器上以分布式模式管理数据,并遵循如 MapReduce 等函数式编程范式。这反过来使得数据处理可以并行执行,充分利用云所提供的分布式计算能力。

使用 NoSQL 数据库还可以以灵活的方式管理数据,而无需在分析变化时重新组织数据的整体结构。

然而,基于关系数据库的传统解决方案需要重新配置几乎整个档案结构,这使得数据在长时间内无法使用。在需要实时验证预测模型准确性并根据此做出业务决策的背景下,这种做法已经不再可接受;这一点在网络安全领域的决策制定中尤为重要。

云交付模型

架构的可扩展性,再加上按需模式管理资源的能力,使得提供商可以提供不同的云交付模型:

  • 基础设施即服务IaaS):提供商部署 IT 基础设施,如存储能力和网络设备。

  • 平台即服务PaaS):提供商部署中间件、数据库等。

  • 软件即服务SaaS):提供商部署完整的应用程序。

IBM Cloud 平台提供了一种交付模型,包括 IaaS 和 PaaS,以及一系列可以集成到组织开发的应用程序中的云服务,例如:

  • 视觉识别:这使得应用程序能够在图像和视频中定位信息,如物体、人脸和文本;平台提供的服务包括检查预训练模型的可用性,以及使用企业数据集进行训练的机会。

  • 自然语言理解:该服务可以基于对文本的分析提取情感信息;如果你想从社交媒体中提取信息(例如,了解在某次信用卡交易中,信用卡持有者是否真的在外地度假),这项服务特别有用。该服务能够识别与人物、地点、组织、概念和类别相关的信息,并且可以通过 Watson Knowledge Studio 根据公司特定的应用领域进行适配。

IBM Cloud 平台还提供一系列用于应用程序开发的高级工具:

  • Watson Studio:这使得项目管理成为可能,并提供团队成员间协作的工具。通过 Watson Studio,可以添加数据源、创建 Jupyter Notebooks、训练模型,并使用许多其他功能来促进数据分析,如数据清洗功能。我们将有机会进一步深入了解 Watson Studio。

  • 知识工作室:这使得根据公司的特定需求开发定制模型成为可能;开发完成后,这些模型可以由 Watson 服务使用,作为预定义模型的补充或替代。

  • 知识目录:这使得公司数据的管理和共享成为可能;该工具还可以执行数据清洗和整理操作,从而通过安全策略对数据访问权限进行概况化管理。

在 IBM 云平台提供的主要优势中,有一个不容忽视的优势,那就是可以实施利用认知计算的先进解决方案。让我们来看一看这是什么。

授权认知计算

人工智能的传播自始至今伴随着过度且毫无根据的担忧;许多作者和评论员预见了灾难性的场景,在这些场景中,机器(在不久的将来)将超越人类。这样的灾难的原因,正是人工智能的崛起。

现实是,尽管计算机取得了惊人的成功,它们仍然是天才型傻瓜。

毫无疑问,计算机的计算能力远超人类,且超出多个数量级;IBM Watson 在“世纪之战”中的胜利——计算机击败了当时的世界象棋冠军加里·卡斯帕罗夫——似乎宣布了人工智能最终战胜人类认知能力的到来。

然而,尽管计算能力有限,人类在许多技能方面依然无可匹敌,比如适应能力、互动能力、判断力等。

比如,我们人类可以一眼认出一个人(或物体),无需经过大量样本数据的训练;只需一张照片(或一张画像),就足以在人群中认出被描绘的人。计算机远未达到这种专业水平。

所以,问题并不是用机器替代人类;相反,眼前最可能的情景是,人类和机器将更加紧密地合作,以日益普及的方式整合彼此的技能。

这就是认知计算的含义:将人类的能力与计算机的计算能力结合起来,携手应对当代社会日益增长的复杂性。

在这种共生关系中,机器将其巨大的计算能力和取之不尽的记忆提供给人类,从而使人类能够增强其判断、直觉、同理心和创造力等能力。

从某种意义上说,通过认知计算,机器不仅使我们能够增强我们的五种自然感官,还赋予了我们第六种人工感官:情境意识。

我们已经多次提到,尤其是在网络安全领域,遇到的一个主要难题是,如何从大量分散且零散的信息中,重建一个准确的整体图景。

面对我们从各个数据源不断接收到的大量数据和信息,人类的能力显得力不从心;大数据分析超出了人类分析的能力,正是因为大数据的特点,包括无数维度(由许多不同的特征以及数据量组成)。

然而,大数据使我们能够定义语义上下文,在此上下文中我们可以进行分析;就好像它们增加了我们的感知能力,添加了无数的人工传感器。

只有机器的计算能力才能过滤我们不断从人工传感器到人类判断技能、直觉中接收到的大量信息,为我们提供整体意义,并使我们能够理解这些信息。

在云端导入示例数据并运行 Jupyter Notebook

dataplatform.cloud.ibm.com/

IBM Watson 主页

为继续注册,选择前面的截图中显示的“试用免费版(注册)”。我们将自动被重定向到注册表单,见下方截图:

IBM Watson 注册页面

注册完成后,我们可以从主页重新登录:

IBM Watson 登录表单

登录后,我们可以创建一个新项目:

IBM Watson 开始创建项目页面

我们可以选择想要创建的项目类型:

IBM Watson 项目选择

在我们的例子中,我们将选择数据科学,如下所示:

IBM Watson 数据科学项目

CREDIT CARD FRAUD DETECTION

IBM Watson 新建项目页面

我们现在可以通过选择“添加到项目 | 数据”将数据集添加到我们的项目中:

IBM Watson-添加数据

要添加数据集,只需点击“查找并添加数据”,然后转到“文件”标签。从那里,您可以点击并添加来自计算机的数据文件。

.csvwww.openml.org/data/get_csv/1673544/phpKo8OWT
creativecommons.org/publicdomain/mark/1.0/www.openml.org/d/1597

数据集包含 31 个数值型输入变量,如时间(表示每笔交易之间的时间间隔)、交易金额和类特征。

类特征是一个二元变量,仅取值 1 或 0(分别表示欺诈或合法交易)。

数据集的主要特点是极度不平衡,欺诈交易仅占所有交易的 0.172%。

添加数据集后,我们可以通过选择“添加到项目 | 笔记本”来将 Jupyter 笔记本添加到项目中,如下截图所示:

IBM Watson-添加笔记本

要创建 Jupyter 笔记本,请执行以下步骤:

  1. 点击创建一个笔记本

  2. 选择标签

  3. 为笔记本输入名称

  4. 可选地,输入笔记本描述

  5. 选择运行时

  6. 点击创建

恭喜!你已经成功配置了项目,并准备好在 IBM Cloud 平台上的 IBM Watson Studio 中查看信用卡欺诈检测模型的实际应用。

使用 IBM Watson Studio 进行信用卡欺诈检测

github.com/IBM/xgboost-smote-detect-fraud/blob/master/notebook/Fraud_Detection.ipynb
.csvpandas

选择下面的单元格,读取数据并将其转换为笔记本中的 DataFrame 部分,然后执行以下步骤:

pandas
# Rename the dataframe to df

df = df_data_2
train_test_split

from sklearn.model_selection import train_test_split

x = df[['Time', 'V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7', 'V8', 'V9', 'V10',
       'V11', 'V12', 'V13', 'V14', 'V15', 'V16', 'V17', 'V18', 'V19', 'V20',
       'V21', 'V22', 'V23', 'V24', 'V25', 'V26', 'V27', 'V28', 'Amount']]
y = df['Class']

xtrain, xtest, ytrain, ytest = train_test_split(x, y, test_size=0.30,
random_state=0)
TimeAmount
Class10
V1V2V28

此时,我们可以引入我们的第一个集成分类器,以测试其在数据集上的分类质量。

RandomForestClassifier

选择落在集成算法中最常用的一个,即随机森林算法。

RandomForestClassifier

该算法是使用袋装技术的学习集成方法,因此特别适用于减少模型的过拟合。

RandomForestClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics

rfmodel = RandomForestClassifier()
rfmodel.fit(xtrain,ytrain)
ypredrf = rfmodel.predict(xtest)

print('Accuracy : %f' % (metrics.accuracy_score(ytest, ypredrf)))

Accuracy : 0.999414

模型的准确率相当高(99.9414%),证明了集成学习的有效性。

让我们看看是否可以通过使用另一个分类器集成,利用提升技术,来改善预测结果。

GradientBoostingClassifier
GradientBoostingClassifier

集成分类器使用的算法采用了提升技术;它还使用梯度下降来最小化成本函数(由各个基础分类器返回的残差误差表示,这些基础分类器也是由决策树构成的)。

在以下代码中,我们可以看到梯度提升集成分类器的应用:

from sklearn import ensemble

params = {'n_estimators': 500, 'max_depth': 3, 'subsample': 0.5,
          'learning_rate': 0.01, 'min_samples_leaf': 1, 'random_state': 3}

clf = ensemble.GradientBoostingClassifier(**params)
clf.fit(xtrain, ytrain) 

y_pred = clf.predict(xtest) 

print("Accuracy is :")
print(metrics.accuracy_score(ytest, y_pred))

Accuracy is : 0.998945085858
RandomForestClassifier
XGBoost

我们现在将通过使用XGBoost来进一步改进预测,XGBoost 是梯度提升算法的改进版,旨在优化性能(使用并行计算),从而减少过拟合。

xgboostXGBClassifier
from sklearn import metrics
from xgboost.sklearn import XGBClassifier

xgb_model = XGBClassifier()

xgb_model.fit(xtrain, ytrain, eval_metric=['error'], eval_set=[((xtrain, ytrain)),(xtest, ytest)])

y_pred = xgb_model.predict(xtest)  

print("Accuracy is :")
print(metrics.accuracy_score(ytest, y_pred))

Accuracy is : 0.999472542929
RandomForestClassifier

评估我们预测的质量

accuracy_score

F1 值

为了方便起见,我们简要回顾一下之前介绍的度量标准及其定义:

敏感度或真正率(TPR)= 真阳性 / (真阳性 + 假阴性);

在这里,敏感度也被称为召回率:

假阳性率(FPR)= 假阳性 / (假阳性 + 真阴性);

精确度 = 真阳性 / (真阳性 + 假阳性)

基于这些指标,可以估算出 F1 得分,它表示精确度和敏感度之间的调和平均数:

F1 = 2 * 精确度 * 敏感度 / (精确度 + 敏感度)

F1 得分可以用来评估从预测中获得的结果;最佳估算值是 F1 接近 1 的值,而最差的估算值对应 F1 接近 0 的值。

ROC 曲线

在假阳性和假阴性之间,通常存在一种权衡;减少假阴性的数量会导致假阳性的增加,为了检测这种权衡,使用了一条特定的曲线,称为 ROC 曲线。如下图所示:

commons.wikimedia.org/wiki/File:ROC_curve.svg
scikit-learnroc_curve()
from sklearn.metrics import roc_curve

FPR, TPR, OPC = roc_curve(targets, probs)
TPRFPROPCTPROPC
# Plotting Sensitivity
plt.plot(OPC,TPR)
OPCTPRTPRFPR
# Plotting ROC curve
plt.plot(FPR,TPR)

AUC(ROC 曲线下的面积)

TPRFPR

我们还可以通过 ROC 曲线下的面积来比较不同的分类器,以找出哪个分类器更准确。

为了理解这种比较的逻辑,我们必须考虑到,在 ROC 空间内,最优分类器是由点x = 0 和 y = 1 的坐标标识的(它们对应的是没有假阴性和假阳性的极限情况)。

为了比较不同的分类器,我们可以计算每个分类器对应的ROC 曲线下面积AUC)值;获得最高 AUC 值的分类器是最准确的。

我们还可以考虑两个特殊分类器的 AUC 值:

  • 最佳分类器的 AUC 是 1 x 1 = 1

  • 最差分类器的 AUC 是 0.5

此外,AUC 也是衡量不平衡数据集的一种指标。

scikit-learnAUC
from sklearn.metrics import auc

AUC = auc(FPR, TPR)

基于我们所说的内容,现在我们可以更准确地评估由我们的分类器得到的预测结果,并相互比较。

比较集成分类器

现在,我们可以通过比较它们来计算每个分类器的主要准确性度量。

RandomForestClassifier 报告

RandomForestClassifier
print('classification report')
print(metrics.classification_report(ytest, ypredrf))
print('Accuracy : %f' % (metrics.accuracy_score(ytest, ypredrf)))
print('Area under the curve : %f' % (metrics.roc_auc_score(ytest, ypredrf)))

classification report
             precision    recall  f1-score   support

          0       1.00      1.00      1.00     17030
          1       0.96      0.73      0.83        33

avg / total       1.00      1.00      1.00     17063

Accuracy : 0.999414
Area under the curve : 0.863607

GradientBoostingClassifier 报告

GradientBoostingClassifier
print('classification report')
print(metrics.classification_report(ytest, y_pred))
print("Accuracy is :")
print(metrics.accuracy_score(ytest, y_pred))
print('Area under the curve : %f' % (metrics.roc_auc_score(ytest, y_pred)))

classification report
             precision    recall  f1-score   support

          0       1.00      1.00      1.00     17030
          1       0.74      0.70      0.72        33

avg / total       1.00      1.00      1.00     17063

Accuracy is : 0.998945085858
Area under the curve : 0.848250

XGBClassifier 报告

XGBClassifier
print('classification report')
print(metrics.classification_report(ytest, y_pred))
print("Accuracy is :")
print(metrics.accuracy_score(ytest, y_pred))
print('Area under the curve : %f' % (metrics.roc_auc_score(ytest, y_pred)))

classification report
             precision    recall  f1-score   support

          0       1.00      1.00      1.00     17030
          1       0.93      0.79      0.85        33

avg / total       1.00      1.00      1.00     17063

Accuracy is : 0.999472542929
Area under the curve : 0.893881
XGBClassifierGradientBoostingClassifier

使用 SMOTE 提高预测准确性

我们通过展示基于过采样的重平衡技术如何有助于提高预测准确性来总结我们的分析。

RandomForestClassifier
from collections import Counter
from imblearn.over_sampling import SMOTE 

x = df[['Time', 'V1', 'V2', 'V3', 'V4', 'V5', 'V6', 'V7', 'V8', 'V9', 'V10',
       'V11', 'V12', 'V13', 'V14', 'V15', 'V16', 'V17', 'V18', 'V19', 'V20',
       'V21', 'V22', 'V23', 'V24', 'V25', 'V26', 'V27', 'V28', 'Amount']]

y = df['Class']

# Increase the fraud samples from 102 to 500

sm = SMOTE(random_state=42,ratio={1:500})
X_res, y_res = sm.fit_sample(x, y)
print('Resampled dataset shape {}'.format(Counter(y_res)))

Resampled dataset shape Counter({0: 56772, 1: 500})

# Split the resampled data into train & test data with 70:30 mix

xtrain, xtest, ytrain, ytest = train_test_split(X_res, y_res, test_size=0.30, random_state=0)

# Random Forest Classifier on resampled data

from sklearn.ensemble import RandomForestClassifier
from sklearn import metrics

rfmodel = RandomForestClassifier()
rfmodel.fit(xtrain,ytrain)

ypredrf = rfmodel.predict(xtest)

print('classification report')
print(metrics.classification_report(ytest, ypredrf))
print('Accuracy : %f' % (metrics.accuracy_score(ytest, ypredrf)))
print('Area under the curve : %f' % (metrics.roc_auc_score(ytest, ypredrf)))

classification report
             precision    recall  f1-score   support

          0       1.00      1.00      1.00     17023
          1       0.97      0.91      0.94       159

avg / total       1.00      1.00      1.00     17182

Accuracy : 0.998952
Area under the curve : 0.955857

由于应用了合成过采样技术,我们可以看到 F1 分数和 AUC 都有所提高。

总结

我们已经学会了如何开发一个信用卡欺诈检测的预测模型,利用 IBM Cloud 平台和 IBM Watson Studio。

通过利用 IBM Cloud 平台,我们还学会了如何解决数据集中与信用卡交易相关的非平衡和非平稳数据的问题,并充分利用了集成学习和数据采样技术。

在下一章中,我们将深入探讨生成对抗网络GANs)。

第九章:GANs - 攻击与防御

生成对抗网络GANs)代表了深度学习在网络安全领域为我们提供的最先进的神经网络示例。GANs 可以用于合法目的,如身份验证程序,但它们也可以被利用来破坏这些程序。

在本章中,我们将讨论以下主题:

  • GANs 的基本概念及其在攻击和防御场景中的应用

  • 开发对抗样本的主要库和工具

  • 通过模型替代对深度神经网络DNNs)的攻击

  • 通过 GANs 对入侵检测系统IDS)的攻击

  • 利用对抗样本对面部识别程序的攻击

我们现在将通过介绍 GANs 的基本概念开始本章内容。

GANs 简述

arxiv.org/abs/1406.2661

GANs 背后的基本思想很简单,它们通过让两个神经网络相互竞争,直到达到一个平衡的结果条件;然而,与此同时,利用这些直觉的可能性几乎是无限的,因为 GANs 能够学习如何模仿并人工重现任何数据分布,无论是面孔、声音、文本,还是甚至是艺术作品。

在本章中,我们将扩展生成对抗网络(GANs)在网络安全领域的应用,了解如何利用它们同时进行攻击(例如针对基于生物特征识别的安全程序的攻击)以及保护神经网络免受通过 GANs 进行的攻击。为了全面理解 GANs 的特点和潜力,我们需要介绍一些关于神经网络NNs)和深度学习DL)的基本概念。

深度学习概述

我们在第四章《恶意软件威胁检测》和第六章《保护用户身份验证》中已经遇到过神经网络(NN)。现在,我们将通过更加系统化的方式进一步探讨深度学习(DL)。深度学习是机器学习ML)的一个分支,旨在模仿人脑的认知能力,试图执行那些典型的高复杂度人类任务,如面部识别和语音识别。因此,深度学习旨在通过引入基于人工神经元的网络来模拟人脑的行为,这些神经元分布在多个层级并相互连接,并且这些层次的深度可以高或低,这也是“深度学习”这一术语中深度一词的由来。

深度学习和神经网络的概念并不新鲜,但仅在近年来,得益于数字架构领域的进展,它们才找到了实际的理论与实践应用,这一进展得到了计算能力的提升、分布式计算通过云计算的充分利用以及大数据分析所带来的几乎无限的训练数据的支持。

深度学习的潜力不仅在研究和商业领域得到了认可,还在网络安全领域得到了广泛应用。在网络安全中,越来越需要使用能够动态适应环境变化的解决方案,这些解决方案不仅采用静态检测工具,还能够动态学习如何自动识别新型攻击的算法,进而通过分析数据集中的代表性特征来发现可能的威胁,尤其是在这些数据集往往是噪声较多的情况下。

与传统的机器学习(ML)相比,从数学角度来看,深度学习也具有更高的复杂性,尤其是在广泛使用微积分和线性代数方面。然而,与机器学习相比,深度学习能够在准确性和算法在不同应用领域的潜在重用方面取得更好的结果。

通过使用互相连接的神经网络(NN)层,深度学习不仅限于分析原始数据集的特征,还能够通过创建新的特征重新组合这些数据,从而适应所需进行的分析的复杂性。

构成深度学习(DL)的人工神经网络层分析接收到的输入数据和特征,并将它们与各个内部层共享,这些内部层反过来处理外部层的输出数据。通过这种方式,从数据集中提取的原始特征被重新组合,产生新的特征,这些特征经过优化以供分析使用。

内部层之间的连接越多,深度和重新组合特征的能力越强,从而更好地适应问题的复杂性,将其分解为更具体、可管理的子任务。

我们已经提到,深度学习(DL)的构成元素是由人工神经元组成的神经网络(NN)层。现在,我们将更详细地研究这些构成元素的特点,从人工神经元开始。

人工神经元和激活函数

我们已经在第三章中遇到过一种特定类型的人工神经元——罗森布拉特的感知器,并且我们已经看到,这种人工神经元通过在超过阈值的正信号出现时自我激活,模拟了人类大脑中神经元的行为。

为了验证阈值以上是否存在正信号,使用了一个特殊的函数,称为激活函数,在感知器的情况下,具有以下特点:

在实际应用中,如果wx值的乘积——即输入数据与相应权重的乘积——超过某个阈值 https://github.com/OpenDocCN/freelearn-dl-pt3-zh/raw/master/docs/hsn-ai-cbrsec/img/ab446c36-e490-4d55-b41c-08b080a54fef.png,则感知器被激活;否则,它保持静止。因此,激活函数的任务就是在验证某些条件后,决定是否激活人工神经元。

激活函数有不同的类型,但最常见的可能是修正线性单元ReLU),在其最简单的版本中,假设将函数*max(0, wx)*应用于输入值(与相应的权重相乘),结果即为激活值。

从形式上看,这可以表示为以下方程:

还有一种变体被称为LeakyReLU,如以下方程所示:

与普通 ReLU 不同,激活函数的泄漏版本返回的是wx的软化值(对于wx的负值,而不是0),这个值是通过应用乘法常数 https://github.com/OpenDocCN/freelearn-dl-pt3-zh/raw/master/docs/hsn-ai-cbrsec/img/666e3062-4473-4fc6-99e6-256c9b4cd643.png得到的,通常该常数的值较小,接近0(但不等于0)。

从数学角度看,ReLU 激活函数代表了一种非线性变换,将输入值与各自权重的乘积关系转化为非线性关系。

通过这种方式,我们能够逼近任何类型的行为,而不必将自己局限于简单的线性关系。我们在第六章《确保用户身份验证》中提到过这一点,当时我们介绍了名为用户检测与多层感知器的章节,展示了如何通过多层感知器MLP)——由多个人工神经元组成的感知器层——克服单一感知器的局限性,通过在神经网络中引入足够数量的神经元来逼近任何连续的数学函数。这种逼近任何连续数学函数的能力正是神经网络的特征,这也决定了它们在学习方面的强大能力。

现在,让我们看看如何从单个人工神经元过渡到神经网络。

从人工神经元到神经网络

我们已经了解了人工神经元的特性以及激活函数执行的任务。接下来,让我们更深入地了解神经网络的特性。神经网络由多层神经元组成,这些神经元共同构成一个网络。神经网络还可以解释为人工神经元图,每个连接都有一个权重。

我们已经说过,通过向神经网络中添加足够数量的神经元,可以模拟任何连续数学函数的行为。实际上,神经网络不过是表示任意复杂度数学函数的一种替代方式。神经网络的强大之处在于它们能够通过创造新的特征来组装从数据集中提取的原始特征。

神经网络中会增加(隐藏层)层,以便执行这种特征组合。随着层数的增加,网络生成新特征的能力也得到了增强。必须特别关注神经网络的训练过程。

训练神经网络的最常见方法之一是前向传播。训练数据作为输入被送入网络的外层,外层将它们的部分处理输出传递给内层,依此类推。内层将对来自外层的输入数据进行处理,并将它们处理后的部分输出继续传递给后续层。

各层所执行的处理通常包括根据预期值评估与单个预测相关的权重的好坏。例如,在监督学习的情况下,我们已经提前知道标记样本的预期值,并根据所选的学习算法调整权重。这将导致一系列计算,通常通过表示与各层神经元相关的参数的偏导数来表示,这些计算需要在各个层中迭代执行,从而在计算上带来了相当大的负担。

随着神经网络中层数的增加,数据在网络中需要经历的步骤数呈指数级增长。为了理解这一点,可以想象一个神经元的输出经过 100 个神经元组成的内部层后,继续传递到另一个由 100 个神经元组成的层,依此类推,直到到达返回最终网络输出的外层神经元。

一种替代的训练策略,显著降低了计算负担,涉及反向传播。与其将从单层获得的部分输出传递到后续层,不如在各个层级上通过整合所获得的值来计算最终输出,通过记忆各个层级获得的输出值。这样,训练就受到将整个网络的输出反向传播的影响。不同于各个层返回的单一输出,权重会根据需要更新,以最小化错误率。

从数学角度看,反向传播是作为矩阵向量的乘积(在计算上要求较低),而不是像前向传播那样进行矩阵矩阵乘法(更多细节请参阅Python 机器学习——第二版,作者:Sebastian Raschka,Packt 出版)。

现在,让我们来看一下最常见的几种神经网络类型:

  • 前馈神经网络(FFNNs):FFNNs 代表了神经网络(NNs)的基本类型。每一层的神经元与下一层的一些(或所有)神经元相连接。FFNNs 的特点是各层之间的连接仅朝一个方向进行,并且没有循环或反向连接。

  • 循环神经网络(RNNs):这些网络的特点是神经元之间的连接形成有向循环,输入和输出都是时间序列。随着数据的积累和分析,RNNs 有助于识别数据中的模式,因此特别适用于执行动态任务,如语音识别和语言翻译。在网络流量分析和静态分析中,RNNs 在网络安全领域被广泛使用。一个 RNN 的例子是**长短期记忆(LSTM)**网络。

  • 卷积神经网络(CNNs):这些网络特别用于执行图像识别任务。CNNs 的特点是能够识别数据中特定特征的存在。构成 CNNs 的层与特定的过滤器相关联,这些过滤器表示感兴趣的特征(例如,表示图像中数字的一组像素)。这些过滤器具有相对于空间平移不变的特性,从而能够检测到搜索空间中不同区域中的感兴趣特征的存在(例如,在图像的不同区域中相同数字的存在)。CNN 的典型架构包括一系列卷积层激活层池化层全连接层。池化层的功能是减小感兴趣特征的大小,以便在搜索空间内查找这些特征。

()

在这对神经网络的快速回顾之后,我们现在准备认识 GANs。

认识 GANs

我们已经提到,GANs 的基本直觉是让两个神经网络相互竞争,以改进总体结果。术语对抗特指这两个神经网络在完成各自任务时相互竞争。这种竞争的结果是一个无法进一步改进的整体结果,从而达到平衡条件。

使用 GANs 的典型例子是实现一个名为生成网络的特定神经网络,其任务是创建模拟真实图像特征的人工图像。第二个神经网络称为判别网络,与生成网络竞争,以区分人工模拟图像与真实图像。

一个有趣的方面是,这两个网络通过实现一种平衡状态(无差异状态)进行协作,它们各自的目标函数优化彼此竞争。生成网络将其优化过程建立在欺骗判别网络的能力上。

判别网络则基于在区分真实图像和由生成网络人工生成的图像时所达到的准确度,执行其优化过程。现在,让我们更详细地看一下这两个神经网络之间的差异。

生成网络与判别网络

理解生成对抗网络(GAN)中各个神经网络(NN)任务的一种直观方式是考虑这样一个场景:判别网络试图正确分类由生成网络人工生成的垃圾邮件。为了展示每个神经网络必须优化的不同目标函数,我们将借助条件概率(这是贝叶斯定理的基础),这一概念我们已经在第三章,垃圾邮件还是正常邮件?利用人工智能检测电子邮件网络安全威胁一节中的朴素贝叶斯垃圾邮件检测部分遇到过。

我们定义P(S|W)为给定电子邮件消息表示垃圾邮件(S)的概率,该概率基于文本中出现可疑词汇(W)。因此,判别网络的任务是正确估计与每封分析过的电子邮件相关的概率P(S|W).

对称地,生成网络的任务正好相反:即估计概率P(W|S)——也就是说,给定一条垃圾邮件,文本中包含可疑词汇(W)的可能性有多大。你会从条件概率理论中回忆到,P(S|W)的值与P(W|S)的值不同,因此这两个神经网络有不同的目标函数需要优化,即使它们是相关的。

因此,判别网络将寻求优化其目标函数,该函数涉及通过正确分类由生成网络人工生成的垃圾邮件,来适当地估计概率P(S|W),而生成网络通过根据每条邮件的概率P(W|S)生成垃圾邮件,从而优化其目标函数。生成网络接着将尝试模拟垃圾邮件,试图欺骗判别网络。同时,判别网络则试图正确识别真实的垃圾邮件,将其与生成网络人工创建的邮件区分开来,通过与先前已分类的真实垃圾邮件样本进行比较。

两个网络通过相互作用进行学习。生成网络生成的虚假垃圾邮件被作为输入传递给判别网络,判别网络将它们与真实垃圾邮件一起分析,逐步细化由P(S|W) 估计值组成的概率估计。这建立了两个神经网络之间的共生关系,在这种关系中,两个网络都试图优化各自的对立目标函数。

这种情况被博弈论定义为零和博弈,而逐步达成的动态平衡,结束了两个网络的优化过程,这就是纳什均衡

纳什均衡

在博弈论的数学理论中,纳什均衡被定义为两个竞争玩家将各自的游戏策略视为他们可以选择的最佳选项的条件。这种平衡状态是玩家通过反复进行博弈学习的结果。

在纳什均衡条件下,每个玩家将选择执行相同的动作,并且不会做出修改。

确定这种平衡的条件是特别严格的。事实上,它们意味着以下几点:

  • 所有玩家都是理性的(也就是说,他们必须最大化自己的目标函数)

  • 所有玩家都知道其他玩家也是理性的,并且知道各自需要最大化的目标函数

  • 所有玩家同时进行博弈,而不了解其他玩家做出的选择

现在,让我们来看一下如何用数学术语表示 GAN。

GAN 背后的数学

我们已经说过,GAN 的目的是实现两个神经网络之间的平衡状态。寻找这个平衡涉及到解决以下方程式,这是一个极小极大条件:

从前面的公式中,你可以看到定义两个神经网络的对抗目标。我们试图最大化D,同时最小化G。换句话说,代表判别器的神经网络D旨在最大化方程式,这转化为最大化与真实样本相关的输出,同时最小化与虚假样本相关的输出。另一方面,代表生成器的神经网络G有相反的目标,即最小化G的失败次数,从而最大化D在面对虚假样本时返回的输出。

GAN 的总体目标是在零和博弈(纳什均衡)中实现平衡,这种平衡特征是一个无差别的条件,其中D的输出将是每个分类样本分配的 50%的概率估计。换句话说,判别器不能可靠地区分真实样本和虚假样本。

如何训练 GAN

训练 GAN 可能需要较高的计算能力;否则,进行训练所需的时间可能从几小时到几天不等。由于两个神经网络之间的相互依赖,建议在训练判别器网络时保持生成器网络返回的值不变。与此同时,使用可用的训练数据对判别器网络进行预训练,再训练生成器网络也是一种有益的做法。

同时,合理设置两个神经网络的学习率也非常重要,以避免判别器网络的学习率超过生成器网络的学习率,反之亦然,从而防止各自的神经网络未能实现其优化目标。

一个 GAN 的示例–模拟 MNIST 手写数字

github.com/eriklindernoren/ML-From-Scratch/blob/master/mlfromscratch/unsupervised_learning/generative_adversarial_network.pygithub.com/eriklindernoren/ML-From-Scratch/blob/master/LICENSEyann.lecun.com/exdb/mnist/
build_generator()build_discriminator()
randomnormal()
noise = np.random.normal(0, 1, (half_batch, self.latent_dim))
train()
train(self, n_epochs, batch_size=128, save_interval=50)
train()
# The generator wants the discriminator to label the generated samples as valid

valid = np.concatenate((np.ones((batch_size, 1)), np.zeros((batch_size, 1))), axis=1)

# Train the generator
g_loss, g_acc = self.combined.train_on_batch(noise, valid)

在下面的图像中,我们可以看到生成对抗网络(GAN)在不同训练周期中的逐步学习进程。GAN 在生成数字图像代表的过程中所取得的进展是显而易见的:

github.com/eriklindernoren/ML-From-Scratch/blob/master/mlfromscratch/unsupervised_learning/generative_adversarial_network.pygithub.com/eriklindernoren/ML-From-Scratch/blob/master/LICENSE
from __future__ import print_function, division
from sklearn import datasets
import math
import matplotlib.pyplot as plt
import numpy as np
import progressbar

from sklearn.datasets import fetch_openml
from mlxtend.data import loadlocal_mnist

from mlfromscratch.deep_learning.optimizers import Adam
from mlfromscratch.deep_learning.loss_functions import CrossEntropy
from mlfromscratch.deep_learning.layers import Dense, Dropout, Flatten, Activation, Reshape, BatchNormalization
from mlfromscratch.deep_learning import NeuralNetwork

GAN__init__()
class GAN():

    def __init__(self):
        self.img_rows = 28 
        self.img_cols = 28
        self.img_dim = self.img_rows * self.img_cols
        self.latent_dim = 100

        optimizer = Adam(learning_rate=0.0002, b1=0.5)
        loss_function = CrossEntropy

        # Build the discriminator
        self.discriminator = self.build_discriminator(optimizer, loss_function)

        # Build the generator
        self.generator = self.build_generator(optimizer, loss_function)

        # Build the combined model
        self.combined = NeuralNetwork(optimizer=optimizer, loss=loss_function)
        self.combined.layers.extend(self.generator.layers)
        self.combined.layers.extend(self.discriminator.layers)

        print ()
        self.generator.summary(name="Generator")
        self.discriminator.summary(name="Discriminator")

build_generator()build_discriminator()
    def build_generator(self, optimizer, loss_function):

        model = NeuralNetwork(optimizer=optimizer, loss=loss_function)

        model.add(Dense(256, input_shape=(self.latent_dim,)))
        model.add(Activation('leaky_relu'))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(512))
        model.add(Activation('leaky_relu'))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(1024))
        model.add(Activation('leaky_relu'))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Dense(self.img_dim))
        model.add(Activation('tanh'))

        return model

    def build_discriminator(self, optimizer, loss_function):

        model = NeuralNetwork(optimizer=optimizer, loss=loss_function)

        model.add(Dense(512, input_shape=(self.img_dim,)))
        model.add(Activation('leaky_relu'))
        model.add(Dropout(0.5))
        model.add(Dense(256))
        model.add(Activation('leaky_relu'))
        model.add(Dropout(0.5))
        model.add(Dense(2))
        model.add(Activation('softmax'))

        return model
train()
    def train(self, n_epochs, batch_size=128, save_interval=50):  

        X, y = loadlocal_mnist(images_path='./MNIST/train-images.idx3-ubyte', labels_path='./MNIST/train-labels.idx1-ubyte')  

        # Rescale [-1, 1]
        X = (X.astype(np.float32) - 127.5) / 127.5

        half_batch = int(batch_size / 2)

        for epoch in range(n_epochs):

            # ---------------------
            #  Train Discriminator
            # ---------------------

            self.discriminator.set_trainable(True)

            # Select a random half batch of images
            idx = np.random.randint(0, X.shape[0], half_batch)
            imgs = X[idx]

            # Sample noise to use as generator input
            noise = np.random.normal(0, 1, (half_batch, self.latent_dim))

            # Generate a half batch of images
            gen_imgs = self.generator.predict(noise)

            # Valid = [1, 0], Fake = [0, 1]
            valid = np.concatenate((np.ones((half_batch, 1)), np.zeros((half_batch, 1))), axis=1)
            fake = np.concatenate((np.zeros((half_batch, 1)), np.ones((half_batch, 1))), axis=1)

            # Train the discriminator
            d_loss_real, d_acc_real = self.discriminator.train_on_batch(imgs, valid)
            d_loss_fake, d_acc_fake = self.discriminator.train_on_batch(gen_imgs, fake)
            d_loss = 0.5 * (d_loss_real + d_loss_fake)
            d_acc = 0.5 * (d_acc_real + d_acc_fake)

            # ---------------------
            #  Train Generator
            # ---------------------

            # We only want to train the generator for the combined model
            self.discriminator.set_trainable(False)

            # Sample noise and use as generator input
            noise = np.random.normal(0, 1, (batch_size, self.latent_dim))

            # The generator wants the discriminator to label the generated samples as valid
            valid = np.concatenate((np.ones((batch_size, 1)), np.zeros((batch_size, 1))), axis=1)

            # Train the generator
            g_loss, g_acc = self.combined.train_on_batch(noise, valid)

            # Display the progress
            print ("%d [D loss: %f, acc: %.2f%%] [G loss: %f, acc: %.2f%%]" % (epoch, d_loss, 100*d_acc, g_loss, 100*g_acc))

            # If at save interval => save generated image samples
            if epoch % save_interval == 0:
                self.save_imgs(epoch)
save_imgs()
    def save_imgs(self, epoch):
        r, c = 5, 5 # Grid size
        noise = np.random.normal(0, 1, (r * c, self.latent_dim))
        # Generate images and reshape to image shape
        gen_imgs = self.generator.predict(noise).reshape((-1, self.img_rows, self.img_cols))

        # Rescale images 0 - 1
        gen_imgs = 0.5 * gen_imgs + 0.5

        fig, axs = plt.subplots(r, c)
        plt.suptitle("Generative Adversarial Network")
        cnt = 0
        for i in range(r):
            for j in range(c):
                axs[i,j].imshow(gen_imgs[cnt,:,:], cmap='gray')
                axs[i,j].axis('off')
                cnt += 1
        fig.savefig("mnist_%d.png" % epoch)
        plt.close()

__main__
if __name__ == '__main__':

    gan = GAN()
    gan.train(n_epochs=200000, batch_size=64, save_interval=400)

现在,让我们继续看看用 Python 开发的 GAN 工具和库。

GAN Python 工具和库

用于开发对抗样本的工具和库(无论是进行攻击还是防御)不断增多。我们将查看其中一些最常见的示例。在本节中,我们将整合常用的库和工具,接下来的章节将分别讨论基于不同攻击和防御策略与场景的特定库和工具。

为了充分理解这些工具和库的实用性,我们需要分析基于神经网络的网络安全解决方案的脆弱性、实施攻击的可能性,以及准备适当防御措施的难度。

神经网络的脆弱性

尽管正如我们之前所看到的,神经网络(NN)近年来因其在解决通常是人类认知能力专属的复杂问题(如面部识别和语音识别)时展现出的巨大潜力,已获得了特别关注,神经网络,尤其是深度神经网络(DNN),仍然存在一些相当重要的脆弱性,这些脆弱性可以通过生成对抗网络(GAN)加以利用。这意味着,举例来说,可能会通过人工创建对抗样本来欺骗基于面部识别或其他生物特征的生物认证程序。

显然无害的设备,如 3D 医学影像扫描仪,已被用作攻击载体,正如最近一篇论文所示,CT-GAN: 使用深度学习恶意篡改 3D 医学影像,作者为以色列本·古里安大学信息系统工程系、Soroka 大学医学中心的 Yisroel Mirsky、Tom Mahler、Ilan Shelef 和 Yuval Elovici(arXiv: 1901.03597v2)。

在这项研究中,作者集中研究了如何将癌症图像注入和移除 CT 扫描,展示了深度神经网络(DNN)对攻击的高度脆弱性。

通过添加虚假证据或删除一些真实的医学图像证据,攻击者如果能访问到医学影像,可以改变患者的诊断结果。

例如,攻击者可以添加或删除脑动脉瘤、脑肿瘤以及其他病理证据,如心脏病的证据。这种类型的威胁展示了 DNN 在处理敏感信息(如健康状况信息)时如何通过几个数量级的扩展攻击面,甚至可能涉及犯罪,如谋杀,且不需要攻击者亲自参与,只需利用数字设备和程序的漏洞作为无菌攻击向量。

从我们所说的内容中,我们可以轻松理解深度神经网络(DNN)在面对对抗性攻击时缺乏鲁棒性所带来的严重性,这可能决定了程序及其依赖应用的妥协性。

然而,在利用 DNN 的应用中,也有一些关键任务应用(例如那些管理自动驾驶汽车功能的应用)。

深度神经网络攻击

对 DNN 进行攻击的基本方法有两种:

  • 白盒攻击:这种攻击假设 DNN 目标模型具有透明性,允许直接验证对抗性示例对响应的敏感性。

  • 黑盒攻击:与前一种情况不同,对抗性示例的敏感性检查是间接实现的,因为无法获得目标神经网络的配置细节;唯一可用的信息是神经网络对发送给它们的相应输入返回的输出值。

无论攻击类型如何,攻击者总是能够利用一些关于神经网络的一般特性。如我们所见,最广泛的对抗性攻击之一是那些旨在欺骗图像分类算法的攻击,利用人工创建的图像样本。因此,考虑到图像分类应用更倾向于使用卷积神经网络CNN),攻击者将更加专注于这种神经网络的漏洞进行攻击。

即使是 DNN 使用的学习策略也可以间接构成攻击向量。我们之前已经看到,反向传播技术因其在计算上的更高效率而被优先用于训练算法。了解这一优先学习选择后,攻击者可以反过来利用梯度下降等算法攻击 DNN,假设反向传播策略允许计算整个 DNN 返回输出的梯度。

对抗性攻击方法

以下是一些最常用的对抗攻击开发方法:

  • 快速梯度符号方法FGSM):为了生成对抗样本,这种方法利用与 DNN 受害者反向传播方法相关的梯度符号。

  • 基于雅可比矩阵的显著性图攻击JSMA):这种攻击方法通过迭代修改信息(例如图像中最显著的像素)来创建对抗样本,基于一个 JSMA 来描述输入和目标神经网络返回输出之间的现有关系。

  • Carlini 和 WagnerC 和 W):这种对抗攻击方法可能是最可靠且最难检测的。对抗攻击被视为一个优化问题,使用预定义的度量(例如欧几里得距离)来确定原始样本与对抗样本之间的差距。

然而,对抗样本也表现出一个有趣的特点:攻击可转移性

对抗攻击的可转移性

对抗攻击的一个典型特点与其可转移性有关。

这一特点指的是,针对某个特定 DNN 生成的对抗样本,可能也能转移到另一个 DNN,因为神经网络具有很高的泛化能力,这正是它们的优势(但同时也是它们的脆弱性)。

利用对抗攻击的可转移性,攻击者能够创建可重用的对抗样本,而无需知道神经网络的个别配置的确切参数。

因此,很可能一组成功欺骗特定 DNN 进行图像分类的对抗样本,能够被用来欺骗其他具有相似分类任务的神经网络。

防御对抗攻击

随着对抗攻击的传播,已经有许多尝试提供适当的防御措施,主要基于以下几种方法:

  • 基于统计的检测防御:这种方法通过利用统计测试和异常值检测来尝试检测对抗样本的存在。它假设描述真实样本和对抗样本的统计分布在根本上是不同的。然而,C 和 W 攻击方法的有效性表明,这一假设并不是显而易见或可靠的。

  • 梯度遮蔽防御:我们已经看到对抗攻击如何利用大多数深度神经网络(DNN)采用的反向传播优化策略,并依赖于目标神经网络执行的梯度计算信息。梯度遮蔽防御因此涉及在神经网络训练过程中隐藏与梯度相关的信息。

  • 对抗训练防御:这种防御方法旨在通过将对抗样本和真实样本插入训练数据集中,使学习算法对可能出现在训练数据中的扰动更加鲁棒。这种防御方法似乎对 C 和 W 对抗攻击最为有效。然而,它也有一定的代价,涉及网络复杂性的增加和模型参数的增加。

现在,DNN 的脆弱性以及对抗攻击和防御方法已被介绍,我们可以分析开发对抗样本时使用的主要库。

CleverHans 对抗样本库

当前备受关注的 Python 库之一无疑是 CleverHans 库,它通常是开发对抗样本的其他库和工具的基础。

github.com/tensorflow/cleverhansgithub.com/tensorflow/cleverhans/blob/master/LICENSE

该库特别适合构建攻击、搭建防御措施,以及基准测试机器学习系统对对抗攻击的脆弱性。

www.tensorflow.org/install/

安装 TensorFlow 后,我们可以使用常规命令安装 CleverHans:

pip install cleverhans

CleverHans 库的众多优点之一是它提供了多个示例和教程,展示了使用不同方法通过模型开发对抗样本的过程。

yann.lecun.com/exdb/mnist/
  • 使用 FGSM 的 MNIST:本教程介绍了如何训练 MNIST 模型,利用 FGSM 制作对抗样本,并通过对抗训练使模型对对抗样本更加鲁棒。

  • 使用 JSMA 的 MNIST:本教程介绍了如何定义一个 MNIST 模型,通过 JSMA 方法制作对抗样本。

  • 使用黑盒攻击的 MNIST:本教程实现了一种基于对抗训练的替代模型的黑盒攻击(即通过观察黑盒模型为精心挑选的输入分配的标签,来模仿黑盒模型的副本)。对抗者然后使用替代模型的梯度来查找那些被黑盒模型错误分类的对抗样本。

在本章中,我们将遇到一些使用 CleverHans 库开发对抗性攻击和防御场景的示例。

EvadeML-Zoo 对抗性示例库

另一个特别值得关注的库是 EvadeML-Zoo。EvadeML-Zoo 是一个用于对抗性机器学习的基准测试和可视化工具,由弗吉尼亚大学的机器学习小组和安全研究小组开发。

github.com/mzweilin/EvadeML-Zoo/blob/master/LICENSEgithub.com/mzweilin/EvadeML-Zoo

EvadeML-Zoo 库提供了一系列工具和模型,包括以下内容:

  • 攻击方法如 FGSM、BIM、JSMA、Deepfool、Universal Perturbations 和 Carlini/Wagner-L2/Li/L0

  • 用于攻击的最先进的预训练模型

  • 对抗性示例的可视化

  • 防御方法

  • 几个现成的可用数据集,如 MNIST、CIFAR-10 和 ImageNet-ILSVRC

下载完包后,你可以使用以下命令在只使用 CPU 的机器上安装 EvadeML-Zoo 库:

pip install -r requirements_cpu.txt

此外,如果你有兼容的 GPU 可用,可以执行以下命令:

pip install -r requirements_gpu.txt

我们已经看到,EvadeML-Zoo 库提供的功能还包括预训练模型,这对于加速对抗性示例的开发过程尤其有用,而这些示例通常在计算上非常消耗资源。

要下载预训练模型,请运行以下命令:

mkdir downloads; curl -sL https://github.com/mzweilin/EvadeML-Zoo/releases/download/v0.1/downloads.tar.gz | tar xzv -C downloads
main.py
main.py
usage: python main.py [-h] [--dataset_name DATASET_NAME] [--model_name MODEL_NAME]
 [--select [SELECT]] [--noselect] [--nb_examples NB_EXAMPLES]
 [--balance_sampling [BALANCE_SAMPLING]] [--nobalance_sampling]
 [--test_mode [TEST_MODE]] [--notest_mode] [--attacks ATTACKS]
 [--clip CLIP] [--visualize [VISUALIZE]] [--novisualize]
 [--robustness ROBUSTNESS] [--detection DETECTION]
 [--detection_train_test_mode [DETECTION_TRAIN_TEST_MODE]]
 [--nodetection_train_test_mode] [--result_folder RESULT_FOLDER]
 [--verbose [VERBOSE]] [--noverbose]

 optional arguments:
 -h, --help            show this help message and exit
 --dataset_name DATASET_NAME
 Supported: MNIST, CIFAR-10, ImageNet, SVHN.
 --model_name MODEL_NAME
 Supported: cleverhans, cleverhans_adv_trained and
 carlini for MNIST; carlini and DenseNet for CIFAR-10;
 ResNet50, VGG19, Inceptionv3 and MobileNet for
 ImageNet; tohinz for SVHN.
 --select [SELECT]     Select correctly classified examples for the
 experiment.
 --noselect
 --nb_examples NB_EXAMPLES
 The number of examples selected for attacks.
 --balance_sampling [BALANCE_SAMPLING]
 Select the same number of examples for each class.
 --nobalance_sampling
 --test_mode [TEST_MODE]
 Only select one sample for each class.
 --notest_mode
 --attacks ATTACKS     Attack name and parameters in URL style, separated by
 semicolon.
 --clip CLIP           L-infinity clip on the adversarial perturbations.
 --visualize [VISUALIZE]
 Output the image examples for each attack, enabled by
 default.
 --novisualize
 --robustness ROBUSTNESS
 Supported: FeatureSqueezing.
 --detection DETECTION
 Supported: feature_squeezing.
 --detection_train_test_mode [DETECTION_TRAIN_TEST_MODE]
 Split into train/test datasets.
 --nodetection_train_test_mode
 --result_folder RESULT_FOLDER
 The output folder for results.
 --verbose [VERBOSE]   Stdout level. The hidden content will be saved to log
 files anyway.
 --noverbose

EvadeML-Zoo 库使用 Carlini 模型和对 MNIST 数据集的 FGSM 对抗性攻击进行执行,具体如下:

python main.py --dataset_name MNIST --model_name carlini \
 --nb_examples 2000 --balance_sampling \
 --attacks "FGSM?eps=0.1;" \
 --robustness "none;FeatureSqueezing?squeezer=bit_depth_1;" \
 --detection "FeatureSqueezing?squeezers=bit_depth_1,median_filter_2_2&distance_measure=l1&fpr=0.05;"

Defense-GAN library
Defense-GAN

在分析 Defense-GAN 库的详细信息之前,让我们先尝试理解它所基于的假设,以及它提供的功能,以实现有效的对抗性攻击防御。

正如我们所见,对抗性攻击可以分为白盒攻击和黑盒攻击;在白盒攻击的情况下,攻击者可以完全访问模型的架构和参数,而在黑盒攻击的情况下,攻击者无法访问模型参数。

我们还知道,许多防御对抗攻击的方法已经被提出,这些方法本质上基于区分对抗样本与真实样本的统计分布(统计检测),基于隐藏与神经网络学习阶段相关的敏感信息(梯度掩蔽),或者基于使用对抗样本与其他训练样本一起训练学习算法(对抗训练)。

所有这些防御方法都有一定的局限性,因为它们只能有效防御白盒攻击或黑盒攻击,但不能同时防御两者。

Defense-GAN 可以作为对抗任何攻击的防御工具,因为它不假设攻击模型,而是简单地利用 GAN 的生成能力来重构对抗样本。

Defense-GAN 提出了一种新的防御策略,该策略基于一个无监督训练的 GAN,在合法(未扰动)训练样本上进行训练,以去噪对抗样本。

github.com/kabkabm/defensegan/blob/master/LICENSEgithub.com/kabkabm/defensegan

下载库后,您可以通过启动以下命令来安装它:

pip install -r requirements.txt
download_dataset.py
python download_dataset.py [mnist|f-mnist|celeba]
train.py
python train.py --cfg  --is_train

 --cfg This can be set to either a .yml configuration file like the ones in experiments/cfgs, or an output directory path.
 can be any parameter that is defined in the config file.

脚本执行将创建:

  • 每个实验的目录都位于输出目录中,并与保存模型检查点的目录同名。

  • 每个实验目录中都会保存一个配置文件,以便可以加载该目录的地址。

  • 每个实验的训练目录都位于输出目录中,并与保存模型检查点的目录同名。

  • 每个实验目录中都会保存一个训练配置文件,以便可以加载该目录的地址。

Defense-GAN 库还提供了一些工具,您可以用来实验不同的攻击模式,从而验证防御模型的有效性。

blackbox.py
python blackbox.py --cfg  \
     --results_dir  \
     --bb_model {A, B, C, D, E} \
     --sub_model {A, B, C, D, E} \
     --fgsm_eps  \
     --defense_type {none|defense_gan|adv_tr}
     [--train_on_recs or --online_training]  

让我们来看一下这里的每个参数:

--cfg--results_dir--bb_model--sub_model--defense_type--train_on_recs--online_trainingDefense-GAN-RecDefense-GAN-Orig--rec_itersL--online_training
--blackbox.py
--rec_itersL--rec_lr--rec_rrR--num_train--num_test--debug
blackbox.py
python blackbox.py --cfg output/gans/mnist \
 --results_dir defensegan \
 --bb_model A \
 --sub_model B \
 --fgsm_eps 0.3 \
 --defense_type defense_gan
whitebox.py
python whitebox.py --cfg  \
        --results_dir  \
        --attack_type {fgsm, rand_fgsm, cw} \
        --defense_type {none|defense_gan|adv_tr} \
        --model {A, B, C, D} \
        [--train_on_recs or --online_training]

whitebox.py
python whitebox.py --cfg  \
        --results_dir whitebox \
        --attack_type fgsm \
        --defense_type defense_gan \
        --model A
blackbox.py--whitebox.py
--rec_itersL--rec_lr--rec_rrR--num_test

现在让我们继续看看如何通过模型替代来对神经网络进行攻击。

通过模型替代进行网络攻击

在黑盒模式下进行对抗攻击所展现的潜力的一个有趣示例是论文Practical Black-Box Attacks against Machine Learning(arXiv: 1602.02697v4)中描述的内容,其中展示了对远程托管的深度神经网络进行攻击的可能性,而攻击者并不知道目标神经网络的配置特征。

在这些情况下,攻击者唯一可用的信息是神经网络根据攻击者提供的输入类型返回的输出。实际上,攻击者观察到 DNN 在针对攻击输入时返回的分类标签。正是在这里,攻击策略变得有趣。实际上,本地替代模型是用一个对抗模型合成生成的输入,并由目标神经网络标记训练的,以代替远程托管的神经网络。

由 MetaMind 托管的神经网络作为远程托管网络目标,公开了一个互联网 DL API。通过将攻击示例提交到托管网络,作者验证了在本地替代模型上训练的对抗示例,RNN 错误地分类了超过 80%的对抗示例。此外,这一攻击策略也在亚马逊和谷歌提供的类似在线服务上进行验证,结果更为糟糕,误分类率高达 96%。

通过这种方式,作者证明了他们的黑盒对抗攻击策略具有普遍有效性,而不仅仅局限于特定选择的目标神经网络。获得的结果还证明了对抗攻击可转移性原理的有效性,使用在本地模型上测试的合成数据集。攻击者实际上是通过充分逼近特征来替代本地模型,用目标模型来替代本地模型,从而能够利用本地模型识别到的漏洞攻击目标模型。

因此,基于模型替代的对抗攻击方法的关键要素是替代模型训练和合成数据集生成。

让我们更仔细地看一下这两个特性。

替代模型训练

如我们之前所说,基于模型替代的对抗攻击方法旨在训练一个替代模型,该模型与原始目标神经网络相似,以便找到目标神经网络上的可行漏洞。

因此,替代模型的训练阶段具有一些重要的特殊性,涉及以下内容:

  • 在没有目标模型知识的情况下选择替代模型的架构

  • 限制对目标模型进行查询的次数,以确保该方法可操作

为了应对这些困难的任务,提出的攻击策略基于合成数据的生成(使用一种称为雅可比矩阵数据增强的技术)。

生成合成数据集

合成数据集生成中的方法在基于模型替代的攻击策略中至关重要。

要理解这一点,你只需要考虑这样一个事实:尽管原则上可以对目标模型进行无限次(甚至是无限数量的)不同查询(以验证目标模型针对每个查询输入生成的输出),但从实际角度来看,这种方法是不可行的。

首先,它是不可持续的,因为大量的查询会使对抗性攻击容易被检测到,而且它也不可持续,因为我们需要根据目标神经网络的潜在输入组件数量,增加发送到目标模型的请求数量。

替代方案涉及使用合适的启发式方法生成合成数据集,基于识别目标模型输出中方向在初始训练点集周围的变化。这些方向通过替代模型的雅可比矩阵来识别,以便通过优先选择样本并在查询目标模型标签时准确地逼近目标模型的决策边界。

用 MalGAN 欺骗恶意软件检测器

黑盒对抗性攻击策略同样可以有效地用来欺骗基于神经网络的下一代反恶意软件系统。

github.com/yanminglai/Malware-GAN/github.com/yanminglai/Malware-GAN/blob/master/LICENSEcuckoo.readthedocs.io/en/2.0.3/virusshare.com/

以下是主 MalGAN 类(版本 2)的代码:

"""
 MalGAN v2 Class definition
 https://github.com/yanminglai/Malware-GAN/blob/master/MalGAN_v2.py
 Released under GPL 3.0 LICENSE: https://github.com/yanminglai/Malware-GAN/blob/master/LICENSE  

 """

 from keras.layers import Input, Dense, Activation
 from keras.layers.merge import Maximum, Concatenate
 from keras.models import Model
 from keras.optimizers import Adam
 from numpy.lib import format
 from sklearn.ensemble import RandomForestClassifier
 from sklearn import linear_model, svm
 from sklearn.model_selection import train_test_split
 import matplotlib.pyplot as plt
 from load_data import *
 import numpy as np
MalGAN()__init__()
 class MalGAN():
     def __init__(self):
         self.apifeature_dims = 74
         self.z_dims = 10
         self.hide_layers = 256
         self.generator_layers = [self.apifeature_dims+self.z_dims, self.hide_layers, self.apifeature_dims]
         self.substitute_detector_layers = [self.apifeature_dims, self.hide_layers, 1]
         self.blackbox = 'RF'
         optimizer = Adam(lr=0.001)

         # Build and Train blackbox_detector
         self.blackbox_detector = self.build_blackbox_detector()

         # Build and compile the substitute_detector
         self.substitute_detector = self.build_substitute_detector()
         self.substitute_detector.compile(loss='binary_crossentropy', optimizer=optimizer, metrics=['accuracy'])

         # Build the generator
         self.generator = self.build_generator()

         # The generator takes malware and noise as input and generates adversarial malware examples
         example = Input(shape=(self.apifeature_dims,))
         noise = Input(shape=(self.z_dims,))
         input = [example, noise]
         malware_examples = self.generator(input)

         # For the combined model we will only train the generator
         self.substitute_detector.trainable = False

         # The discriminator takes generated images as input and determines validity
         validity = self.substitute_detector(malware_examples)

         # The combined model  (stacked generator and substitute_detector)
         # Trains the generator to fool the discriminator
         self.combined = Model(input, validity)
         self.combined.compile(loss='binary_crossentropy', optimizer=optimizer)

MalGANblackbox_detector
     def build_blackbox_detector(self):

         if self.blackbox is 'RF':
             blackbox_detector = RandomForestClassifier(n_estimators=50, max_depth=5, random_state=1)
         return blackbox_detector

     def build_generator(self):

         example = Input(shape=(self.apifeature_dims,))
         noise = Input(shape=(self.z_dims,))
         x = Concatenate(axis=1)([example, noise])
         for dim in self.generator_layers[1:]:
             x = Dense(dim)(x)
         x = Activation(activation='sigmoid')(x)
         x = Maximum()([example, x])
         generator = Model([example, noise], x, name='generator')
         generator.summary()
         return generator

     def build_substitute_detector(self):

         input = Input(shape=(self.substitute_detector_layers[0],))
         x = input
         for dim in self.substitute_detector_layers[1:]:
             x = Dense(dim)(x)
         x = Activation(activation='sigmoid')(x)
         substitute_detector = Model(input, x, name='substitute_detector')
         substitute_detector.summary()
         return substitute_detector
blackboxtrain()
     def train(self, epochs, batch_size=32):

         # Load the dataset
         (xmal, ymal), (xben, yben) = self.load_data('mydata.npz')
         xtrain_mal, xtest_mal, ytrain_mal, ytest_mal = train_test_split(xmal, ymal, test_size=0.20)
         xtrain_ben, xtest_ben, ytrain_ben, ytest_ben = train_test_split(xben, yben, test_size=0.20)

         # Train blackbox_detector
         self.blackbox_detector.fit(np.concatenate([xmal, xben]),
                                    np.concatenate([ymal, yben]))

         ytrain_ben_blackbox = self.blackbox_detector.predict(xtrain_ben)
         Original_Train_TPR = self.blackbox_detector.score(xtrain_mal, ytrain_mal)
         Original_Test_TPR = self.blackbox_detector.score(xtest_mal, ytest_mal)
         Train_TPR, Test_TPR = [Original_Train_TPR], [Original_Test_TPR]
         best_TPR = 1.0
         for epoch in range(epochs):

             for step in range(xtrain_mal.shape[0] // batch_size):
                 # ---------------------
                 #  Train substitute_detector
                 # ---------------------

                 # Select a random batch of malware examples
                 idx = np.random.randint(0, xtrain_mal.shape[0], batch_size)
                 xmal_batch = xtrain_mal[idx]
                 noise = np.random.uniform(0, 1, (batch_size, self.z_dims))   #noise as random uniform
                 idx = np.random.randint(0, xmal_batch.shape[0], batch_size)
                 xben_batch = xtrain_ben[idx]
                 yben_batch = ytrain_ben_blackbox[idx]

                 # Generate a batch of new malware examples
                 gen_examples = self.generator.predict([xmal_batch, noise])
                 ymal_batch = self.blackbox_detector.predict(np.ones(gen_examples.shape)*(gen_examples > 0.5))

                 # Train the substitute_detector
                 d_loss_real = self.substitute_detector.train_on_batch(gen_examples, ymal_batch)
                 d_loss_fake = self.substitute_detector.train_on_batch(xben_batch, yben_batch)
                 d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)               

我们将按如下方式训练生成器:


                 idx = np.random.randint(0, xtrain_mal.shape[0], batch_size)
                 xmal_batch = xtrain_mal[idx]
                 noise = np.random.uniform(0, 1, (batch_size, self.z_dims))

                 # Train the generator
                 g_loss = self.combined.train_on_batch([xmal_batch, noise], np.zeros((batch_size, 1)))

             # Compute Train TPR
             noise = np.random.uniform(0, 1, (xtrain_mal.shape[0], self.z_dims))
             gen_examples = self.generator.predict([xtrain_mal, noise])
             TPR = self.blackbox_detector.score(np.ones(gen_examples.shape) * (gen_examples > 0.5), ytrain_mal)
             Train_TPR.append(TPR)

             # Compute Test TPR
             noise = np.random.uniform(0, 1, (xtest_mal.shape[0], self.z_dims))
             gen_examples = self.generator.predict([xtest_mal, noise])
             TPR = self.blackbox_detector.score(np.ones(gen_examples.shape) * (gen_examples > 0.5), ytest_mal)
             Test_TPR.append(TPR)

             # Save best model
             if TPR < best_TPR:
                 self.combined.save_weights('saves/malgan.h5')
                 best_TPR = TPR
__main__
 if __name__ == '__main__':
     malgan = MalGAN()
     malgan.train(epochs=50, batch_size=64)

现在,让我们继续说明利用 GAN 进行 IDS 规避的技术。

通过 GAN 进行 IDS 规避

我们在第五章《基于 AI 的网络异常检测》中详细讨论了 IDS,了解了这些设备在当前这种网络攻击不断增加、恶意软件威胁日益扩散的背景下所发挥的微妙作用。

因此,有必要引入能够及时检测可能的恶意软件威胁的工具,防止它们在整个企业网络中扩散,从而危及软件和数据的完整性(例如,想想日益蔓延的勒索软件攻击)。

为了能够及时有效地执行——即减少——误报的数量,因此有必要为 IDS 系统配备能够充分分类分析流量的自动化程序。因此,现代 IDS 系统采用机器学习算法,也越来越多地借助深度神经网络(如 CNN 和 RNN)来提高入侵检测的准确性。

因此,连入侵检测系统IDS)也不能视为对对抗性攻击免疫,这些攻击是专门为欺骗 IDS 的基础模型而生成的,从而降低(甚至消除)正确分类异常流量的能力。

尽管如此,迄今为止,仍然有少数理论研究和软件实现利用对抗性样本对 IDS 进行攻击。

arxiv.org/pdf/1809.02077

介绍 IDSGAN

同时,在 IDSGAN 的情况下,攻击类型基于黑盒策略,其中目标 IDS 的实现细节和配置是未知的。

IDSGAN 的基础 GAN 通常包括两个对抗性的神经网络,其中生成器组件负责通过构造对抗性样本将原始网络流量转换为恶意流量。

IDSGAN 的判别器组件则负责正确分类流量,模拟黑盒检测系统,从而为生成对抗样本的生成器组件提供必要的反馈。

www.unb.ca/cic/datasets/nsl.html

IDSGAN 的特点

IDSGAN 提供的主要功能如下:

  • 通过模拟 IDS 的行为开发攻击的能力

  • 利用对抗样本在黑盒模式下对 IDS 进行攻击的能力

  • 将人工生成流量的检测率降到零的能力

  • 重用生成的对抗样本以攻击不同类型的 IDS 的能力

现在,让我们来看一下 IDSGAN 的结构。

IDSGAN 训练数据集

www.unb.ca/cic/datasets/nsl.html

然后,NSL-KDD 数据集作为基准,既验证生成器组件的有效性,又允许判别器组件返回创建对抗样本所需的反馈。因此,选择 NSL-KDD 数据集并非偶然,因为流量数据样本包含正常和恶意流量,细分为四个主要类别,如探测(probe)、拒绝服务DoS)、用户到根U2R)和根到本地R2L)。

此外,数据集根据 41 个复杂特征展示流量,其中 9 个特征为离散值,剩余的 32 个特征为连续值。

这些特性可以进一步分为以下四种类型:

  • 内在:这些特性反映了单个连接的固有特征

  • 内容:这些特性标记与可能的攻击相关的连接内容

  • 基于时间:这些特性检查过去 2 秒内已建立的连接,这些连接与当前连接具有相同的目标主机或相同的服务

  • 基于主机:这些特性监视过去 100 个连接中与当前连接具有相同目标主机或相同服务的连接

在数据预处理阶段,特别关注特征值之间的维度影响减少。采用基于最小-最大标准的方法进行归一化,将输入数据转换并使其落入区间[0, 1],从而能够管理离散特征和连续特征。

用于执行此归一化的数学公式如下:

这里,x表示归一化前的特征值,*x′*是归一化后的特征值。

一旦我们分析了训练数据集和数据归一化,我们就可以继续研究 IDSGAN 组件的特性。

生成器网络

与所有 GAN 一样,生成器网络是负责生成对抗样本的组件。

在 IDSGAN 中,生成器将原始输入流量样本转换为与大小为m的向量相关联的样本,该向量表示原始样本的特征,另一个维度为n的向量,其中包含噪声——即从均匀分布中提取的随机数,其值落在[0, 1]范围内。

生成器网络由五个层组成(其中与 ReLU 激活函数相关联),用于管理内部层的输出,而输出层具有足够的单元,以满足原始的m维样本向量。

正如我们所预期的那样,生成器网络根据从判别器网络(模拟 IDS 在黑箱模式下的行为)收到的反馈调整其参数。

现在,让我们更详细地看看 IDSGAN 判别器组件的特性。

判别器网络

我们已经提到,IDSGAN 实现的攻击策略遵循黑箱模式,这意味着假设攻击者对目标 IDS 的实现没有任何了解。从这个角度来看,IDSGAN 的判别器组件试图模拟被攻击的 IDS,通过将生成器组件输出与正常流量示例进行比较,来分类其输出。

这样,判别器能够为生成器提供必要的反馈,以便生成对抗样本。因此,判别器组件由一个多层神经网络组成,其训练数据集包含正常流量和对抗样本。

判别器网络的训练阶段如下:

  • 正常样本和对抗样本由 IDS 进行分类

  • IDS 的结果用作判别器的目标标签

  • 判别器使用结果训练数据集来模拟 IDS 分类

用于训练生成器和判别器组件的算法将在接下来的章节中概述。

理解 IDSGAN 的算法训练

为了训练生成器网络,使用来自判别器网络对对抗样本分类结果的梯度。目标函数,也称为损失函数—以下方程中的L表示,生成器网络必须最小化的函数—由以下方程组成:

这里,GD分别表示生成器和判别器网络,而S**[attack]表示原始恶意样本,MN分别表示与原始流量样本匹配的m维向量和与噪声部分匹配的n维向量。

对于判别器网络,训练是通过优化由以下方程表示的目标函数进行的:

正如我们所看到的,判别器网络的训练数据集包含了正常样本和对抗性样本,而目标标签则由 IDS 返回的输出表示。

因此,在目标函数中,s 代表用于判别器训练的流量样本,而 B[normal]B[attack] 分别代表 IDS 正确预测的正常样本和对抗性样本。

使用 GAN 进行人脸识别攻击

作为 GAN 使用的最后一个例子,我们将看到可能是最具象征性和最著名的案例,它涉及生成代表人类面孔的对抗性样本。

除了这一技术对结果检查者可能产生的惊人效果(这些结果通常非常真实),当它作为攻击工具使用时,它构成了对所有基于生物识别证据验证的网络安全程序的严重威胁(这些程序常用于访问例如在线银行服务,或更近期的社交网络登录,甚至是访问你的智能手机)。

此外,它甚至可以用来欺骗警方用于识别嫌疑人的 AI 驱动的人脸识别工具,从而降低其整体可靠性。

正如论文《解释与利用对抗性样本》中所证明的(arxiv: 1412.6572,其作者包括首次将 GAN 引入世界的 Ian Goodfellow),你只需要引入微小的扰动(人眼无法察觉),就可以构建出能够欺骗神经网络分类器的人工图像。

以下是从一张著名图片中复制的内容,其中一只熊猫由于注入原始样本的微小扰动而被错误分类为长臂猿:

(图片摘自论文《解释与利用对抗性样本》– 1412.6572)

人脸识别对抗攻击的脆弱性

普通人脸识别模型易受对抗攻击的原因在于使用了两个相同的 CNN,它们共同构成了一个连体网络。为了计算要比较的两张人脸的代表性图像之间的距离,一个 CNN 与第一张图像结合,另一个 CNN 与第二张图像结合。

计算表示之间的距离——也称为输出嵌入,由 CNN 相对于各自图像的表示形式进行——是根据超过给定阈值来评估的。

这种人脸识别方法的薄弱环节恰恰在于正确评估与单独图像相关联的嵌入输出之间的距离,以验证是否超过决定图像匹配失败的阈值。

因此,攻击者如果想替代合法用户被识别,例如,为了登录在线银行网站或社交网络,应该尝试通过未经授权访问存储 CNN 输出嵌入的数据库来获取这些嵌入。另一种方式是,攻击者可以通过利用对抗示例攻击,欺骗 Siamese 网络,冒充任何用户。

对 FaceNet 的对抗示例

github.com/tensorflow/cleverhans/blob/master/examples/facenet_adversarial_faces/facenet_fgsm.pygithub.com/tensorflow/cleverhans/blob/master/LICENSE
FGSM

以下是对 FaceNet 库实现的面部识别模型进行对抗攻击的示例代码:

"""
 Script name: facenet_fgsm.py  
 https://github.com/tensorflow/cleverhans/blob/master/examples/facenet_adversarial_faces/facenet_fgsm.py
 Released under MIT LICENSE:  
 https://github.com/tensorflow/cleverhans/blob/master/LICENSE
 """

 import facenet
 import tensorflow as tf
 import numpy as np
 from cleverhans.model import Model
 from cleverhans.attacks import FastGradientMethod

 import set_loader

InceptionResnetV1Model
 class InceptionResnetV1Model(Model):
   model_path = "models/facenet/20170512-110547/20170512-110547.pb"

   def __init__(self):
     super(InceptionResnetV1Model, self).__init__(scope='model')

     # Load Facenet CNN
     facenet.load_model(self.model_path)
     # Save input and output tensors references
     graph = tf.get_default_graph()
     self.face_input = graph.get_tensor_by_name("input:0")
     self.embedding_output = graph.get_tensor_by_name("embeddings:0")

   def convert_to_classifier(self):
     # Create victim_embedding placeholder
     self.victim_embedding_input = tf.placeholder(
         tf.float32,
         shape=(None, 128))

     # Squared Euclidean Distance between embeddings
     distance = tf.reduce_sum(
         tf.square(self.embedding_output - self.victim_embedding_input),
         axis=1)

     # Convert distance to a softmax vector
     # 0.99 out of 4 is the distance threshold for the Facenet CNN
     threshold = 0.99
     score = tf.where(
         distance > threshold,
         0.5 + ((distance - threshold) * 0.5) / (4.0 - threshold),
         0.5 * distance / threshold)
     reverse_score = 1.0 - score
     self.softmax_output = tf.transpose(tf.stack([reverse_score, score]))

     # Save softmax layer
     self.layer_names = []
     self.layers = []
     self.layers.append(self.softmax_output)
     self.layer_names.append('probs')

   def fprop(self, x, set_ref=False):
     return dict(zip(self.layer_names, self.layers))

我们现在准备好利用 FGSM 方法执行我们的攻击:


 with tf.Graph().as_default():
   with tf.Session() as sess:
     # Load model
     model = InceptionResnetV1Model()
     # Convert to classifier
     model.convert_to_classifier()

     # Load pairs of faces and their labels in one-hot encoding
     faces1, faces2, labels = set_loader.load_testset(1000)

     # Create victims' embeddings using Facenet itself
     graph = tf.get_default_graph()
     phase_train_placeholder = graph.get_tensor_by_name("phase_train:0")
     feed_dict = {model.face_input: faces2,
                  phase_train_placeholder: False}
     victims_embeddings = sess.run(
         model.embedding_output, feed_dict=feed_dict)

     # Define FGSM for the model
     steps = 1
     eps = 0.01
     alpha = eps / steps
     fgsm = FastGradientMethod(model)
     fgsm_params = {'eps': alpha,
                    'clip_min': 0.,
                    'clip_max': 1.}
     adv_x = fgsm.generate(model.face_input, **fgsm_params)

     # Run FGSM
     adv = faces1
     for i in range(steps):
       print("FGSM step " + str(i + 1))
       feed_dict = {model.face_input: adv,
                    model.victim_embedding_input: victims_embeddings,
                    phase_train_placeholder: False}
       adv = sess.run(adv_x, feed_dict=feed_dict)

因此,FGSM 将遵循两种不同的攻击策略:

  • 冒充攻击(该攻击旨在冒充特定用户),使用属于不同个体的面部图像对

  • 躲避攻击(该攻击旨在将自己识别为任何可能的用户),使用属于同一人的面部图像对

现在让我们来看一下如何对 FaceNet 的 CNN 发起对抗攻击。

对 FaceNet 的 CNN 发起对抗攻击

为了运行针对 FaceNet CNN 的对抗攻击示例,请按照以下步骤操作:

github.com/davidsandberg/facenet/wiki/Validate-on-LFW.pb
model_path = "models/facenet/20170512-110547/20170512-110547.pb"
  1. 使用以下命令启动 Python 脚本:
python facenet_fgsm.py

摘要

在本章中,我们探讨了利用 GAN 创建的对抗示例进行的攻击与防御技术。

我们研究了使用 GANs 对越来越多成为网络安全程序核心的 DNNs 可能带来的具体威胁,例如恶意软件检测工具和生物识别。除了与 NNs 广泛应用于敏感数据管理相关的风险,如健康数据,这些威胁导致了基于 GAN 的新型攻击形式,甚至可能 compromise 公民的健康和生理安全。

在下一章中,我们将学习如何通过多个示例评估算法。