傳統的機器學習除了使用Tfidf-ngram的方式外還有其他做特征工程方式,還可以通過定義不同維度的特征來做特征工程,這種特征工程方式需要安全工程師對每一種攻擊有良好特征提取能力。這種方法舉個例子來說可以這樣理解,我的輸入是姚明,此時我在特征工程階段需要將姚明轉化為身高2.2米、體重400斤等等數值特征,再經過標準化等轉化為機器可以識別的量綱單位進行學習預測。

機器學習流程&特征工程
傳統的機器學習可以理解成是生產算法的算法。需要人來先做特征提取,然后再把特征向量化后交給機器去訓練。為什么要做特征工程,有這么一句話在業界廣泛流傳:數據和特征決定了機器學習的上限,而模型和算法只是逼近這個上限而已。我們做特征工程的目的是為了讓訓練后的結果達到最優的狀態。

本例中我們的目的是從流量中識別惡意流量,首先需要在所有的負例樣本中篩選出最具代表的特征,在所有的負例樣本中篩選出最具代表的特征,我們先從簡單關鍵詞特征開始。觀察正例樣本基本沒有類似information_schema.table、 sleep() 、alert(/1/)這種的特殊字符。
format=xml&platform=ppap&channel=withoutchannelfilename=sgim_eng.zip&h=B2EF665558623D671FC19AC78CA2F0F3&v=8.0.0.8381&ifauto=1
md5=d10015a0eb30bd33bb917e1d527c649num=8&PaperCode=600054daid=41&clientuin=1264523260
clientkey=00015947C124007000F19A1CB5D10832A25TAG=ieg.qqpenguin.desktopdaid=41&clientuin=1264523260
觀察負例樣本可以將如下負例樣本看作是請求的value部分如http://x.x.x/path?key1=value1&key2=value2,可以觀察到同類型攻擊具有很多相同的特征,比如xss來說具有很多JAVAscript、alert、onerror=等特征,sql注入具有informationschema、informationschema.table、select、from、where等關鍵詞特征
<form id="test" /><button form="test"formaction="JavaScript:alert(123)">TESThtml5FORMACTION<scriptitworksinallbrowsers>/<script */alert(1)</script<metahttp-equiv="refresh" content="0;url=javascript:confirm(1)"></textarea><script>alert(/xss/)</script>'><script>alert(document.cookie)</script><form><isindexformaction="javascript:confirm(1)"alert(String.fromCharCode(88,83,83));'))"><inputtype="text" value=``<div/onmouseover='alert(1)'>X</div><BODY ONLOAD=alert('helloxworldss')><![><img src="]><img src=x onerror=alert(XSS)//"><inputonblur=write(XSS) autofocus><input autofocus>
本例抽取部分的xss負例樣本,從中可以抽取的特征規則大致可以這樣表示

即便如此仍然會存在很多變形特征,比如<script/**/>、console.log()、<Script>,所以進行一步完善特征工程這一次我們將特征分為兩個維度,第一個維度是詞特征,第二是符號維度,同時對所有的大小寫進行統一轉換為小寫,對于請求的value是url這種可能會存在很多特殊符號的鏈接特征,在本例中可以進行統一降噪轉換為"x"避免受到此類特征等影響學習結果

這里特別說明一下特征除此之外的緯度還有很多,playload的長度、請求響應時間、該ip或該開源指紋請求次數等等,這里我們只用了2個維度來簡單說明。我們繼續將特征進行進行量化,可以大致得到如下每條playload內容對應的特征向量

在處理請求的過程中難免會出現特質編碼[8,40],[9,35]類似這樣具有奇異性的特征編碼,在機器學習領域中我們需要將量綱和量綱單位限定在一個空間同樣的數量級范圍內,經過處理后的數據會消除奇異值帶來的影響,以便我們進行綜合對比評判。
min-max標準化
這里簡單說一下標準化,min-Max就是把數據按比例縮放,使之落入一個小的空間里。同時不改變原有的正態分布,特征數據的取值范圍并不在[ 0,1 ]之間,這點跟歸一化不同。如下其中X代表要轉換的對象,[Newmax,Newmin]代表范圍區間。

收入范圍最低收入12000,最高收入98000,標準化映射到[0,1]之間,現在要將一個人收入是73600進行標準化,映射后的結果如下

代碼示例
數據預處理,這里正負樣本數據結構就不再重復了,保證一個都是惡意樣本,一個是正常樣本即可。
def loadFile():
badXss = "./badx.txt"
goodXss = "./goox.txt"
bf = [x.strip().lower() for x inopen(badXss, "r").readlines()]
gf = [x.strip().lower() for x inopen(goodXss, "r").readlines()]
return bf, gf
特征工程階段,一條playload或者正常樣本后進行特征提取,特征拆分成兩個維度,一個維度是關鍵詞特征,一個維度是關鍵符號特征
def MakeFeature(x):
charList = ["onmouseover=","onload=", "onerror=", "javascript","alert", "src=", "confirm", "onblur"]
markList = ["=", ":",">", "<", '"', "'", ")","(", "."]
featureList = []
for i in x:
char_count, mark_count = 0, 0
payload =urllib.parse.unquote(i.lower().strip())
for charts in charList:
char_count = payload.count(charts)+ char_count
for marks in markList:
mark_count = payload.count(marks) +mark_count
featureList.Append([char_count,mark_count])
return featureList
訓練階段拆分40%測試集,這里筆者使用了多個算法分別進行訓練,目的是想看一下幾個算法在相同數據集下的訓練時間和效果
def train(x, y):
x_train, x_test, y_train, y_test =train_test_split(x, y, test_size=0.4, random_state=666)
param = {'n_estimators': 200, 'max_depth':200, 'min_samples_split': 2, 'learning_rate': 0.01}
NBM = [MultinomialNB(alpha=0.01), # 多項式模型-樸素貝葉斯
BernoulliNB(alpha=0.01),
DecisionTreeClassifier(max_depth=100),
RandomForestClassifier(criterion='gini', max_depth=100,n_estimators=200),
LogisticRegression(random_state=40,solver='lbfgs', max_iter=10000, penalty='l2',multi_class='multinomial',class_weight='balanced', C=100),
LinearSVC(class_weight='balanced',random_state=100, penalty='l2',loss='squared_hinge', C=0.92, dual=False),
SVC(kernel='rbf', gamma=0.7, C=1),
# GradientBoostingClassifier(param)
]
NAME = ["多項式", "伯努利", "決策樹", "隨機森林", "線性回歸", "linerSVC", "svc-rbf"]
for model, modelName in zip(NBM, NAME):
model.fit(x_train, y_train)
pred = model.predict(x_test)
dts = len(np.where(pred == y_test)[0])/ len(y_test)
print("{} 精度:{:.5f} ".format(modelName, dts * 100))
joblib.dump(model, './model.pkl')
預測概率,加載模型進行精度預測
def predicts(x):
clf = joblib.load('./model.pkl')
return clf.predict(x)
def run():
badx, goodx = loadFile()
goodx = MakeFeature(goodx)
badx = MakeFeature(badx)
goody = [0] * len(goodx)
bady = [1] * len(badx)
min_max_scaler = preprocessing.MinMaxScaler()
X_train_minmax =min_max_scaler.fit_transform(bady)
x = np.array(goodx + badx).reshape(-1, 2)
y = np.array(goody + bady).reshape(-1, 1)
train(x, y)
testX =["<script>alert(1)</script>", "123123sadas","onloads2s", "scriptsad23asdasczxc","onload=alert(1)"]
x =MakeFeature(testX)
forres, req in zip(predicts(x), testX):
print("XSS==>" if res == 1else "None==>", req)
預測結果
XSS==>alert(1)
None==> 123123sadas
None==> onloads2s
None==>scriptsad23asdasczxc
XSS==>onload=alert(1)“””
結果
可以看到由于特征工程階段做的特征維度不夠多特征保留的不夠充分,在白樣本中存在大量的干擾特征,導致最后準確率召回率都不是很高,精度大約只有74%左右,使用這種特征工程的方法筆者不是很推薦,雖然有監督方式的機器學習具有良好的可解釋性,但是維護特征是一個永無止盡的過程,難度你真的想有多少智能就有多少人工嗎。

原文地址:freebuf.com/articles/web/223481.html