SQLインジェクションの検出(N-gram編)
ログ情報の数値化
前回は、HTTPのログのエントロピーを算出した。
今回は、N-gramを使った数値化について、流れとしては、以下になる。
- ログを1文字つづ区切る(N-gram, uni-gram)
- 文字ごとのベクトル化(BoW)
- ベクトルの重みづけ(tf-idf)
こちらの書籍を参考にさせて頂いております。
GitHub - oreilly-japan/ml-security-jp: 『セキュリティエンジニアのための機械学習』のリポジトリ
自然言語処理
自然言語処理(しぜんげんごしょり、英語: natural language processing、略称:NLP)は、人間が日常的に使っている自然言語をコンピュータに処理させる一連の技術
言語をコンピュータに処理させるためには、数値化する必要があり、その手法がいろいろとあります。そららのN-gram、BoW、tf-idfについて、まとめます。
N-gram
n個の単語や文字のまとまりを表します。
I have a pen. という文章があった場合、N=1の場合、それぞれの単語である「I」「have」「a」「pen」「.」となる。
N=2の場合、「I have」「have a」「a pen」「pen.」となる。
N=1の場合をuni-gram(ユニグラム)、
N=2、bi-gram(バイグラム)、
N=3,tri-gram(トライグラム)、
と呼ばれている。
日本語の場合は、英語と違い、単語がつながっているので、それを品詞に分けることを形態素解析と呼ぶ。
今回のSQLインジェクションの解析のためのHTTPログは、単語は考慮せず、文字列を1文字づつ区切る、uni-gramを使用する。
BoW
BoWはBag of Wordsの略。直訳すれば、言葉の入れ物。uni-gramで得られた単語(文字)が、何回使われているかカウントしたもの。
You say yes, I say no.という文章のBoWは、say:2それ以外の単語は、それぞれ1となる。
uni-gramでBowを使えば、前回やったエントロピーは算出できる。
tf-idf
tf-idfは以下の2つの意味。
- tf(term frequency:単語頻度)
- idf(inverse document frequency:逆文書頻度)
前者は、BoWから全体の割合を算出したもの
後者は、単語が、どれくらい少ない頻度で存在するかを算出したもの
tfだけでは、よく出てくる単語=重要でない、場合もあり、
逆に、滅多に出ない単語=重要かも?、ということを加味した指標。
計算方法など、こちらが詳しかった。
Pythonでのコード
ここまでの処理は、TfidfVectorizerが一気にやってくれます。
from sklearn.feature_extraction.text import TfidfVectorizerimport numpy as npimport pandas as pd
# ベクトル化のためのオプションの設定、文字を対象にユニグラムを行うvec_opts = {"ngram_range": (1, 1),"analyzer": "char","min_df" : 0.1}
#HTTPリクエストの内容例
# TfidfVectorizerの初期化v = TfidfVectorizer(**vec_opts)# ベクトル化の実行X = v.fit_transform(string)
# tf-idfの出力features = v.get_feature_names()df = pd.DataFrame(X.toarray())df.columns = featuresdf
実行結果は以下の通り。
ブランクについて、0.529238という値など、文字列に含まれる各文字に対するtf-idfの値が算出できた。
以上により、文字列を数値化できたので、あとはお決まりの機械学習の流れに放り込めば、SQLインジェクションの検出器の出来上がり。
補足
自然言語処理で、Skip-gram、CBOWという言葉が出てくる。これらは、Word2Vecと言われる手法で使用されるディープラーニングのモデル。
Word2Vecは、Googleが開発して、自然言語処理の性能を飛躍的に高めたと言われている。
標的型メールを分類させる処理を考える場合、自然言語処理の手法を用いてメールを読ませて、分類できるのかもしれない。