背景:很多情况下,对于异常URL的判别是一项重要的工作,特别是在风控或者是安全防护的环境下。而在很多情况下,是无法获取很多跟URL本身相关的信息源的。比如,数据源受限,你无法获取到URL相关的数据。或者是对于URL判别有实时性的要求,所以无法通过爬取URL的任何内容来提取特征进行判断。
方案:在以上的限定情况下,唯一能使用的关于URL的特征只有URL文本本身。所以,如何通过url文本挖掘来进行异常模式的判别,是具有意义的。同时,通过最近大热的神经网络,能够对url进行自动提取特征,表示学习的效果要比人工构造特征更好。
URL文本挖掘模式?
对于url文本挖掘来说,主要通过几种方式:
-
【固定切词】
通过对url进行按固定模式切词,比如按照『/』以及『:』等进行切分,然后对切分后的相关特征进行分析建模。-
优点:
1. 每个切词都有明确的划分含义。
2. 模型的可解释性强。 -
缺点:
1. 需要手动确认需要切分词。
2. 每个划分域的可能性太多,导致数据字典过大,训练数据相对来说稀疏,不容易训练。
3. 采用划分域过宽,丢失细节信息过多。
-
优点:
-
【k-gram切词】
通过对url按照固定长度切词,比如按照k-gram进行切词,切词完之后的list成为文本构成词语进行分析建模。-
优点:
1. 无需进行固定切分词确认。 -
缺点:
1. 需要对参数k进行合适的调参,来获取有意义的切分效果。
2. 同时如果k较大的时候,词库可能会非常大,导致不易获取好的embeding效果。
-
优点:
-
【字母切词】
通过对url按照单个字母进行切词,将每一个字母视为构成句子的基本单元,然后进行分析建模。为k-gram中k为1的特殊情况。-
优点:
1. 无需调参。
2. 固定切分词确认。 -
缺点:
1. 丢失了网址本身划分字段的信息。
2. 模型解释能力较弱。
-
优点:
【结论】
通过上述的优缺点分析,在数据量不大,尽可能避免丢失信息量,并且对于模型的解释性要求不高的情况下,采用【字母切词】作为url文本挖掘的算法,相对来说预期效果会更好。
从0到1构建算法
-
数据前期处理
【步骤一】:设定url统一长度。
通过对所有url的长度的分布进行统计画出长度分布图,这里需要考虑的问题主要是在不损失过多的url信息长度的条件下,尽可能的降低需要考虑的url长度来提升神经网络的构建复杂度和计算效率(当然,如果你的数据量和计算能力足够的情况下,考虑max长度可能会是保留信息量更好的方式)。基本设定的原则是要让80%左右的url保留80%以上的信息长度。当然,这个数字也是可以调的超参数。【步骤二】:转换url字母到对应字典数字。
主要通过Python中printable中对于常见所有字符的收录作为字典。将对应url字母转换为printable中字母对应的index。这一步将字符类型的向量转换为one-hot编码的数字格式。-
【步骤三】:补齐url长度。
这一步的主要目的是为了将左右的向量长度整理成一致的长度,适合作为神经网络的输入。利用Keras中的API,代码如下:from keras.preprocessing import sequence url_features = sequence.pad_sequences(url_int_tokens, maxlen=max_len)
-
神经网络构建
-
【第一层】:Embeding Layer
主要采用word2vec的embeding层,对one-hot编码转换为有意义的向量形式。这一层融合在整个训练神经网络中,方便后续梯度训练更新的时候,不断更新embeding层的参数。同时,因为url单字母的embeding具有场景和切分的特殊性,不采用对其他迁移embending参数refine的方式。emb = Embedding(input_dim=max_vocab_len, output_dim=emb_dim, input_length=max_len, W_regularizer=regularizers.l2(weight_reg))(main_input)
-
【第二层】:1D-CNN Layer
添加一层一维的CNN,采用Inception结构。主要目的是更丰富的抽取不同深度上下文相关的特征。conv1 = Convolution1D(kernel_size=conv_kernel_size, filters=conv_filters, border_mode='same')(emb) conv2 = Convolution1D(kernel_size=conv_kernel_size + 3, filters=conv_filters, border_mode='same')(emb) conv3 = Convolution1D(kernel_size=conv_kernel_size - 2, filters=conv_filters, border_mode='same')(emb) conv = Add()([conv1, conv2, conv3])
-
【第三层】:1D-MaxPooling Layer
添加一层最大池化层,对url字符数据进行降维处理,最后得到对url的压缩张量表示。这一步的目的,一是为了压缩上下文信息;二是为了降低网络参数的数量,防止在数据量不大的情况下,神经网络过于复杂导致的过拟合。conv = MaxPooling1D(pool_size=max_pool_size)(conv)
-
【第四层】:LSTM Layer
采用浅层LSTM,对url的时序信息进行整理和提取。lstm = LSTM(lstm_output_size)(conv)
-
【第五层】:Fully-Connected Layer
在最后增加一层全连接层,来判断是否是异常url的概率。output = Dense(1, activation='sigmoid', name='output')(lstm)
【附加】
在层与层之间可以增加一些dropout和batchnormalization的层,来对模型进行正则化,以保持模型良好的泛化能力。
-
-
效果分析
从最后的效果来看,对于url字符组织有意义和分层明确url的识别效果较好。但是对于存在随机生成字符模式(如图片名)的url的区分识别效果有待提高,或者通过文本挖掘对这类随机字符模式的url的挖掘精确达到了理论上的极限,有待后续分析。
附:
GitHub项目地址: