1. 程式人生 > >學點算法搞安全之apriori

學點算法搞安全之apriori

[] calc ans prompt 實現 興趣 深度 應用 目標

前言   在企業安全建設專題中偶爾有次提到算法的應用,不少同學想深入了解這塊,所以我專門開了一個子專題用於介紹安全領域經常用到的機器學習模型,從入門級別的SVM、貝葉斯等到HMM、神經網絡和深度學習(其實深度學習可以認為就是神經網絡的加強版)。 技術分享 關聯規則挖掘   關聯規則挖掘通常是無監督學習,通過分析數據集,挖掘出潛在的關聯規則,最典型的一個例子就是尿布和啤酒的故事。相傳沃爾瑪的數據分析人員通過分析大量購物清單發現相當一部分消費者會同時購買尿布和啤酒,結果他們把尿布和啤酒赫然擺在一起出售,結果銷量又雙雙增長。關聯規則分析的結果是客觀現象的體現,有的顯然易見,比如同時購買三文魚和芥末,有的勉強可以解釋,比如尿布和啤酒,有的就匪夷所思,比如打火機和奶酪。關聯算法中最著名的就是apriori算法。 apriori簡介
  首先介紹三個基本概念,支持度、置信度和頻繁k項集。   支持度,P(A ∩ B),既有A又有B的概率,它表現的是A和B兩個事件相對整個數據集合同時發生的頻繁程度,比如尿布和啤酒的支持度是0.2,表明有20%的消費清單中,消費者同時購買了尿布和啤酒。   置信度,P(B|A),在A發生的事件中同時發生B的概率 P(AB)/P(A),它表現的是在AB兩個事件的相關程度,和整個數據集合的大小沒有關系,比如尿布和啤酒的置信度為0.8,表明在同時購買了兩者的消費者中,購買尿布的80%又購買了啤酒。   需要特別說明的是,P(A ∩ B)=P(B ∩ A),但是P(B|A)和P(A|B)是兩回事。   如果事件A中包含k個元素,那麽稱這個事件A為k項集事件A滿足最小支持度閾值的事件稱為頻繁k項集。   apriori算法就是挖掘同時滿足最小支持度閾值和最小置信度閾值的關聯規則。 apriori基本原理
  Apriori算法使用頻繁項集的先驗知識,使用一種稱作逐層搜索的叠代方法,k項集用於探索(k+1)項集。首先,通過掃描事務(交易)記錄,找出所有的頻繁1項集,該集合記做L1,然後利用L1找頻繁2項集的集合L2,L2找L3,如此下去,直到不能再找到任何頻繁k項集。最後再在所有的頻繁集中找出強規則,即產生用戶感興趣的關聯規則。   其中,Apriori算法具有這樣一條性質:任一頻繁項集的所有非空子集也必須是頻繁的。因為假如P(I)< 最小支持度閾值,當有元素A添加到I中時,結果項集(A∩I)不可能比I出現次數更多,因此A∩I也不是頻繁的。 apriori的應用   在安全領域,aprioir的應用非常廣泛,凡是需要挖掘潛在關聯關系的都可以嘗試使用,比如關聯waf的accesslog與後端數據庫的sqllog,識別ssh操作日誌中異常操作等。 我們這裏以分析accesslog為例子。我們從xssed網站的樣例以及waf的攔截日誌中提取xss攻擊日誌作為樣本,示例日誌如下: /0_1/?%22onmouseover=‘prompt(42873)‘bad=%22%3E /0_1/api.php?op=map&maptype=1&city=test%3Cscript%3Ealert%28/42873/%29%3C/script%3E /0_1/api.php?op=map&maptype=1&defaultcity=%e5%22;alert%28/42873/%29;// 我們目標是分析出潛在的關聯關系,然後作為SVM、KNN等分類算法的特征提取依據之一。機器沒有辦法直接識別日誌,需要逐行將日誌文本向量化,最簡單的方式就是按照一定的分割符切割成單詞向量,示例代碼如下: myDat=[] with open("xss-train.txt") as f: for line in f: tokens=re.split(‘\=|&|\?|\%3e|\%3c|\%3E|\%3C|\%20|\%22|<|>|\\n|\(|\)|\‘|\"|;|:|,‘,line) myDat.append(tokens) f.close() 切割後的向量示例如下: [‘/0_1/‘, ‘‘, ‘onmouseover‘, ‘‘, ‘prompt‘, ‘42873‘, ‘‘, ‘bad‘, ‘‘, ‘‘, ‘‘, ‘‘] [‘/0_1/api.php‘, ‘op‘, ‘map‘, ‘maptype‘, ‘1‘, ‘city‘, ‘test‘, ‘script‘, ‘alert%28/42873/%29‘, ‘/script‘, ‘‘, ‘‘] 我們以十分嚴格的置信度來運行,試圖找到關聯關系接近100%的情況: L, suppData = apriori(myDat, 0.1) rules = generateRules(L, suppData, minConf=0.99) 有趣的現象出現了: frozenset([‘//‘, ‘1‘]) --> frozenset([‘‘, ‘alert‘]) conf: 1.0 frozenset([‘1‘, ‘script‘]) --> frozenset([‘‘, ‘/script‘]) conf: 1.0 frozenset([‘/‘, ‘script‘]) --> frozenset([‘‘, ‘/script‘]) conf: 0.997576736672 frozenset([‘type‘, ‘title‘]) --> frozenset([‘a‘, ‘‘]) conf: 0.996108949416 frozenset([‘a‘, ‘title‘]) --> frozenset([‘‘, ‘type‘]) conf: 0.993210475267 frozenset([‘a‘, ‘c‘]) --> frozenset([‘‘, ‘m‘]) conf: 1.0 frozenset([‘1‘, ‘/‘, ‘script‘]) --> frozenset([‘‘, ‘/script‘]) conf: 1.0 frozenset([‘1‘, ‘alert‘, ‘script‘]) --> frozenset([‘‘, ‘/script‘]) conf: 1.0 frozenset([‘alert‘, ‘/‘, ‘script‘]) --> frozenset([‘‘, ‘/script‘]) conf: 0.997416020672 frozenset([‘1‘, ‘alert‘, ‘/‘, ‘script‘]) --> frozenset([‘‘, ‘/script‘]) conf: 1.0 有些結果容易理解,比如‘script‘和‘1‘出現的話會100%的概率導致‘/script‘,有些結果匪夷所思,比如‘a‘和‘c‘出現的話會100%的概率導致‘m‘。 apriori的代碼實現
網上apriori的代碼實現很多,這裏給出其中一種實現。
def createC1(dataSet):
   C1 = []
   for transaction in dataSet:
       for item in transaction:
           if [item] not in C1:
               C1.append([item])
   C1.sort()
   return map(frozenset, C1)
def scanD(D, Ck, minSupport):
   ssCnt = {}
   for tid in D:
       for can in Ck:
           if can.issubset(tid):
               ssCnt[can] = ssCnt.get(can, 0) + 1
   numItems = float(len(D))
   retList = []
   supportData = {}
   for key in ssCnt:
       support = ssCnt[key] / numItems
       if support >= minSupport:
           retList.insert(0, key)
       supportData[key] = support
   return retList, supportData
def aprioriGen(Lk, k):
   retList = []
   lenLk = len(Lk)
   for i in range(lenLk):
       for j in range(i + 1, lenLk):
           L1 = list(Lk[i])[: k - 2];
           L2 = list(Lk[j])[: k - 2];
           L1.sort();
           L2.sort()
           if L1 == L2:
               retList.append(Lk[i] | Lk[j])
   return retList
def apriori(dataSet, minSupport=0.5):
   C1 = createC1(dataSet)
   D = map(set, dataSet)
   L1, suppData = scanD(D, C1, minSupport)
   L = [L1]
   k = 2
   while (len(L[k - 2]) > 0):
       Ck = aprioriGen(L[k - 2], k)
       Lk, supK = scanD(D, Ck, minSupport)
       suppData.update(supK)
       L.append(Lk)
       k += 1
   return L, suppData
def calcConf(freqSet, H, supportData, brl, minConf=0.7):
   prunedH = []
   for conseq in H:
       conf = supportData[freqSet] / supportData[freqSet - conseq]
       if conf >= minConf:
           print freqSet - conseq, ‘-->‘, conseq, ‘conf:‘, conf
           brl.append((freqSet - conseq, conseq, conf))
           prunedH.append(conseq)
   return prunedH
def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
   m = len(H[0])
   if len(freqSet) > m + 1:
       Hmp1 = aprioriGen(H, m + 1)
       Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)
       if len(Hmp1) > 1:
           rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
def generateRules(L, supportData, minConf=0.7):
   bigRuleList = []
   for i in range(1, len(L)):
       for freqSet in L[i]:
           H1 = [frozenset([item]) for item in freqSet]
           if i > 1:
               rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
           else:
               calcConf(freqSet, H1, supportData, bigRuleList, minConf)
   return bigRuleList

學點算法搞安全之apriori