返回 登录
1

使用Keras和Tensorflow检测恶意请求

原文Detecting Malicious Requests with Keras & Tensorflow
作者:Adam Kusey
翻译:雁惊寒

摘要:本文介绍了如何使用Keras框架来构建LSTM RNN来对正常或者恶意的网络请求进行区分。以下是译文。

安全是任何一个Web应用需要关注的东西。良好的开发实践有助于抵御黑客试图窃取数据或攻击应用程序的行为。然而,并不是所有的攻击都能被抵挡住,并不是每一次攻击都会被发现。而安全软件则可以帮你监控和抵御各种未知的攻击。

那么,是否可以利用Google的Tensorflow这个强大的引擎来判断某个请求是否是恶意的呢?这就是我在参加Slalom最近的AI hackathon时想要回答的问题。本文简单介绍了一个安全监控程序的PoC技术细节,该应用程序是在其他几个Slalom参与者的协助下构建起来的。

目标

我们的目标是构建一个能够对传入的请求进行分析并对可疑活动进行标记的应用程序。该应用程序有一个简单的界面来显示这些标记过的请求,并能在必要的时候采取预防措施。我们给这个恶意请求检测程序起了个绰号,名叫“SecuritAI”。

1.jpeg

与其他的机器学习问题一样,数据是构建智能模型的宝贵资源。因此,我们需要通过API来访问请求日志。我们要构建一个模拟API,以生成一个访问日志数据集。日志记录器要添加到模拟API中,以便可以批量地访问日志,并将日志传输出去进行实时处理。

2.png

入门

本项目的第一步是选择一个适合于解决此问题的预测模型,该模型用于检测某个给定的请求是否会破坏或窃取敏感信息。首先,我们决定把焦点放在判断某个请求是否包含了尝试注入攻击的相关内容。注入攻击有多种形式:将SQL、XML、JSON或源代码巧妙地插入到请求中。我们只想知道给定的请求是否存在尝试注入,因此这只是一个二元分类问题。有很多模型可以用来解决这个问题:K-NN、朴素贝叶斯分类器、支持向量机(SVM)、神经网络无监督模型

学术界和实际应用领域目前正时刻关注着深度学习和神经网络的最新进展。事实证明,深度学习和神经网络在图像识别和自然语言处理(NLP)方面表现出众。我们是否可以利用神经网络的NLP能力来处理这个分类问题呢?这就是我们想要测试的。

我们通过模拟API给出JSON形式的访问请求日志,如下所示:

{
  "timestamp": 1502135820943,
  "method": "get",
  "query": {
    "query": "Lawn & Garden Buying Guides"
  },
  "path": "/search",
  "statusCode": 200,
  "source": {
    "remoteAddress": "22.73.58.187",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"
  },
  "route": "/search",
  "headers": {
    "host": "localhost:8002",
    "connection": "keep-alive",
    "cache-control": "no-cache",
    "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
    "accept": "*/*",
    "accept-encoding": "gzip, deflate, br",
    "accept-language": "en-US,en;q=0.8,es;q=0.6"
  },
  "requestPayload": null,
  "responsePayload": "SEARCH"
}

JSON格式的数据是不能用作神经网络模型的输入的。模型的输入必须是数字,因此,需要对文本进行预处理。由于请求日志的内容包含各种字符串、符号和数字,因此,我们选择将每个日志条目预处理为字符序列。

将日志条目作为字符序列进行处理,就是将请求日志文本中的每个字符映射到字典中的数字。相关联的数字表示该字符出现的频率。这个字典最初是用训练数据来创建和拟合的,这样,后续的字符就可以映射到以前曾经出现过的字符上去。例如,在字典中,“,”字符是训练数据集中第七个出现频率最高的字符:

{" ": 39, "(": 77, ",": 7, "0": 8, "4": 26, "8": 28, "<": 64, "D": 71, "H": 59, "L": 61, ...

字符序列学习的一个不错的选择是使用递归神经网络(RNN)。更具体点说,就是选择使用RNNs的长短期记忆网络(LSTM)变体,因为它在学习序列的应用中被广泛使用并取得了成功。 LSTM有点复杂,但这并不是这篇文章的重点,不过如果在高层次上对此有一点了解的话,在修改模型时会有一些帮助。更多有关序列学习和LSTM的实践可以在Andrej Karpathy编写的RNNs的不合理有效性一文中找到。

为了快速开发神经网络模型,我们选择使用运行在Tensorflow之上的高级Keras API,而不是直接使用Tensorflow。通过使用Keras为Tensorflow提供的样板设置,我们能够节约很多时间,并快速地构建起模型原型。

Keras的神经网络模型使用起来非常容易,只需实例化一个模型对象,然后就可以添加层了!初始的嵌入层指定了矢量输入的预期维度,LSTM隐藏层则由64个神经元以及单独的压差层来定义以减少方差,最后则是密集输出层以产生分类置信度。

model = Sequential()
model.add(Embedding(num_words, 32, input_length=max_log_length))
# Prevent overfitting using dropout method of regularization
model.add(Dropout(0.5))
model.add(LSTM(64, recurrent_dropout=0.5))
model.add(Dropout(0.5))
# Condense to single binary output value
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# Training set automatically split 75/25 to check validation loss/accuracy at each epoch
model.fit(X_train, Y_train, validation_split=0.25, epochs=3, batch_size=128, callbacks=[tb_callback])
# Evaluation of separate test dataset performed after training
score, acc = model.evaluate(X_test, Y_test, verbose=1, batch_size=128)

训练

使用LSTM RNN二元分类法则意味着是在模型上应用监督学习算法。因此,训练数据集中的每个日志条目都需要有一个附带的标签来描述该记录的请求是正常的还是尝试注入攻击的。

0 = Normal request log entry
1 = Request log indicates attempted injection attack

对于生成数据来训练模型,则可以使用模拟API来模拟一个非常简单的电子商务应用程序。例如,模拟出/login、 /search、/checkout等URL。由于我们并没有真实用户去访问模拟API,因此我们需要引入一些运行时选项来运行服务器并自动执行请求。我们将这些自动化的请求流量调整为每分钟100次,这样训练数据集的日志就能快速积累起来。

通过将自定义的日志记录器添加到服务器框架中,可以输出指定格式的数据集。为了区分正常和恶意请求,需要在所有的恶意请求前添加一个“attack”头。通过检查是否存在“attack”头来确定每个请求日志条目的标签。如果“attack”头存在,则使用“1”来标记日志,并在写入日志之前删除“attack”头,否则将日志标记为“0”。

由于使用模拟API来生成训练数据集存在一些限制,并且为了确保得到一个更广义的分类器,我们在预处理期间仅提取几个必要的日志字段。这些属性包括:“method”、“query”、“statusCode”、“path”、“requestPayload”。可以使用额外的数据、预处理和可能的单独分类器来分析请求的内容。

自动化客户会放那连续运行了几个小时,以积累一定数量的训练数据。为了快速训练模型,我们将使用AWS p2.xlarge深度学习EC2实例。 AWS的深度学习AMI预先安装了大多数的流行AI库和API,你可以使用GPU进行大量的训练。这个EC2实例每小时90美分的成本不仅节省了在大量数据集上训练模型的时间,还节省了安装和配置Tensorflow使之能够在GPU上正常运行的时间。我们发现在新机器上安装和配置Tensorflow相当地耗时。

为了减少偏差,生成的数据集中包含了大约50/50个正常和恶意的请求日志。该数据集分为75%的训练子集和25%的验证子集。经过几次迭代之后,该模型能够获得相当高的精度。


3.png
从大约23000个请求日志样本得到的训练结果

上图中的准确度和损失指标也会通过Keras训练脚本中附带的Tensorboard回调记录在日志中。这些日志是训练期间检查点的积累,这对于在训练期间和之后将模型的性能可视化非常有用。

实现

有了训练过的模型,现在是时候来实现SecuritAI用户界面程序了,该应用程序用于托管模型以进行实时的预测。与模拟API一样,我们坚持使用自己最熟悉的JavaScript语言。我们构建了一个React UI,作为监视来自请求日志流活动的仪表板。该请求日志流使用AWS Kinesis来管理,用于桥接模拟API和SecuritAI UI之间的通信。

有一个小问题…… Keras是一个python库,那么模型是如何在JavaScript中进行预测的呢?幸运的是,有一个npm包可以用来实现这个需求,那就是keras-js! Keras-js允许JavaScript应用程序运行在Tensorflow引擎上训练Keras模型。这个库使得我们能够在Node.js应用服务器上运行所有的东西。

有关keras-js的更多信息,请参阅: https://github.com/transcranial/keras-js

演示


4.gif
SecuritAI演示

经验教训与后期改进

总体而言,这是一个非常有趣的应用程序,从开发过程中你可以学到有关在Keras中使用Tensorflow建模的知识。也许已经有其他更加简单的机器学习模型或平台可以被用来代替LSTM RNN,但是如果没有一点黑客精神的话,乐趣何在?在理想情况下,无监控异常检测模型可能更适合于本应用。

作为后期的改进,该模型可以转换为仅依赖Tensorflow API来运行、针对内容更丰富的请求头进行训练,以及执行多元分类以实现对可疑请求的分类。

GitHub上的代码:
adamkusey/securitai-ui
adamkusey/securitai-lstm-model

评论