機器學習之KNN檢測惡意流量

2020-01-02 27938人圍觀 ,發現 8 個不明物體 WEB安全

背景

任何智能活動的都可以稱為人工智能,而機器學習(Machine Learning)屬于人工智能的一個分支,深度學習(Deep Learning)則是機器學習的分支。近年來,隨著基礎設施的完善,海量大數據的積累,機器學習方法理論越來越成熟,算力的大幅度提升,互聯網企業也越來越愿意增大在AI領域的投入,AI的優勢在于處理海量數據提取捕獲其中有用信息上發揮著非常重要的作用,如OCR領域圖片鑒黃、自然語言處理方面的惡意言論捕獲、風控領域畫像、推薦系統等。

AI.png

概念

算法分類 解決什么問題
分類算法 是什么
回歸算法 是多少
聚類算法 怎么分
數據降維 怎么壓
強化學習 怎么做

目的

通過機器學習的方式識別惡意流量

特征工程

使用sklearn的TFIDF、2ngram進行分詞

什么是TF-IDF

TF-IDF是一種統計方法,用以評估一字詞對于一個文件集或一個語料庫中的其中一份文件的重要程度。字詞的重要性隨著它在文件中出現的次數成正比增加,但同時會隨著它在語料庫中出現的頻率成反比下降。如果某個單詞在一篇文章中出現的頻率TF高,并且在其他文章中很少出現,則認為此詞或者短語具有很好的類別區分能力,適合用來分類。如果包含詞條t的文檔越少, IDF越大,則說明詞條具有很好的類別區分能力。

詞頻(TF) = 某個詞在文章中的出現次數

逆文檔頻率(IDF) = log(語料庫的文檔總數/包含該詞的文檔總數+1)

公式:TF-IDF = TF * IDF

舉例:假設一篇文章中由1萬個詞組成,其中“跨站腳本”,“web”,“安全”,“攻擊”幾個詞各出現100次,那么他們對應的詞頻TF就是 TF = 100/10000 = 0.01。

語料庫中一共有1000篇文章,其中包含“跨站腳本”的有9篇,包含“web”的有89篇,包含“安全”的有399篇,包含“攻擊”的有499篇,那他們對應的TDF如下,由TFIDF值可知這篇文章重點應該是在講“跨站腳本”

IDF TF*IDF
跨站腳本 log(1000/10)=6.9 6.9 * 0.01 =0.069
web log(1000/90)=4.7 4.7 * 0.01 =0.047
安全 log(1000/400)=3.2 3.2 * 0.01 =0.032
攻擊 log(1000/500)=2.9 2.9 * 0.01 =0.029

流程

數據集正例樣本10萬,數據集負例樣本5萬,由于初始負例樣本不足,可以在特征工程階段將負例樣本*2擴大負例樣本的數據集數量,但效果不會很明顯,一般在深度學習的時候特征樣本不足我會這樣做數據擴展。

對數據做一些基礎的特征工程對連續的數字或單獨的數字都轉化為’8′,將quries里的https|http轉化成同一個特征量等等

label 0 標記正例樣本,label 1 標記負例樣本

class LR(object):
        def __init__(self):

        self.goodX = self.DecodeQuery("./goodX.txt")

        self.badX = self.DecodeQuery("./badqX.txt")

        self.goodY = [0] * len(self.goodX)

        self.badY = [1] * len(self.badX)

        self.vectorizer = TfidfVectorizer(ngram_range=(1, 3))

        self.X = self.vectorizer.fit_transform(self.goodX + self.badX)
def DecodeQuery(self, fileName):
    data = [x.strip() for x in open(fileName, "r").readlines()]
    query_list = []
    for item in data:
        item = item.lower()
        if len(item) > 50 or len(item) < 5:
            continue        
        h = HTMLParser()
        item = h.unescape(item)
        item = parse.unquote(item)
        item, number = re.subn(r'\d+', "8", item)
        item, number = re.subn(r'(http|https)://[a-zA-Z0-9\[email protected]&/#!#\?:]+', "http://u", item)
        query_list.append(item)
    return list(set(query_list))

模型訓練與預測

train_test_split函數用于將矩陣隨機劃分為訓練子集和測試子集,并返回劃分好的訓練集測試集樣本和訓練集測試集標簽,其中test_size是代表要劃分出多少的數據做為測試集,random_state是種子,也就是說當random_state不為0時,每次train_test_split生成的數據集是一致的,以便與我們在初期階段保持數據集一致進行調試。

模型使用KNN(K-Nearest neigbour,KNN)Cover和Hart在1968年提出了最初的鄰近算法。所謂KNN,就是K個最近鄰居的意思。說的是每個樣本都可以用它最接近的k個鄰居來代表。屬于一種有監督的分類(Classification)算法,同時屬于懶惰學習(lazy learning)即KNN沒有顯式的學習過程,也就是沒有訓練數據的階段,所以也代表了該階段的時間開銷為零,數據集事先已有了分類和特征值,待收到新樣本后直接進行處理。

image.png

KNN三要素

1.K值的選擇:對于K值的選擇,如果K值較小表示使用較小鄰域中的樣本進行預測,訓練誤差會減少,但是模型會變得復雜,容易過擬合。

2.距離的度量:一般使用歐幾里得距離

3.決策規則:分類模型中使用多數表決的方式或者加權表決(距離與權重成反比);在回歸模型中,使用平均值法

KNN的優化

當如果有大量的數據輸入的時候為了加快檢索,引入了優化算法,相當于是使用了特殊的結構來保存數據,以減少數據的檢索次數。

KNN的使用

    def TrainModel(self):

        X_train, X_test, y_train, y_test = train_test_split(self.X, self.goodY + self.badY, test_size=0.2, random_state=16)

        knn = neibours.KNeiborsClassifier(n_neibours=5)

        knn.fit(X_train, y_train)

        joblib.dump(knn, "knn.pickle")

在做模型訓練的時候,尤其是在訓練集上做交叉驗證,通常想要將模型保存下來,然后放到獨立的測試集上測試,scikit-learn已經有了模型持久化的操作,存儲模型(持久化)一般就兩種方式一種是joblib和pickle

倒入模塊 from sklearn.externals import joblib

保存模型 joblib.dump(model,’filename.pkl’)

讀取模型 joblib.load(modelName)

    def Predicts(self, modelName, fileName):

        knn = joblib.load(modelName)

        input_x = self.DecodeQuery(fileName)

        X_predict = self.vectorizer.transform(input_x)

        res = knn.predict(X_predict)

        res_list = []

        for url , y in zip(input_x, res):

            label = '正常請求' if y == 0 else '惡意請求'

            print(label , url )

最終預測結果

這里算法筆者用的KNN,但KNN屬于懶惰算法,最大但缺點之一在于在數據量龐大的時候運算會非常的慢,另外一個會受離群點的影響,這個knn的例子只適合做試驗講解,因為KNN具有良好的可解釋性上

惡意請求 /cgi-home/ion-p?page=../../../../../etc/passwd

惡意請求 <svg><script xlink:href=data:,alert(8) />

惡意請求 /./\/././\/././\/././\/././\/././\/././\/./{file}

正常請求 /scripts_photositeprinting/

正常請求 /main.php?stuff="&ver&rem\xa8

總結

機器學習比較痛苦的是調參數、做特征工程,本文沒有特意去做特征工程使用了ngram分詞實現的特征,調參的話懶人可以通過GridSearch和RandomizedSearchCV進行搜索,下篇換個例子來介紹。

寫此文的目的地是筆者在學習過程中踩了很多坑,也是逐步在梳理自己認知的過程,也希望多一些相關的文章給正在研究或剛入門同學多一些參考,學無止境,不喜勿噴哈。

*本文原創作者:鄒先生007,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載

相關推薦
發表評論

已有 8 條評論

取消
Loading...

特別推薦

活動預告

填寫個人信息

姓名
電話
郵箱
公司
行業
職位
css.php 微信上那些说赚钱是真的吗