技術者ブログ
クラウド型WAF「Scutum(スキュータム)」の開発者/エンジニアによるブログです。
金床“Kanatoko”をはじめとする株式会社ビットフォレストの技術チームが、“WAFを支える技術”をテーマに幅広く、不定期に更新中!

ビッグデータ解析による比較では、WAFはUNION SELECTだけでブロックしてもよさそう?!
はじめに
初期のScutumはUNION SELECTという文字列があると単純にSQLインジェクションであると判断して、通信をブロックしていました。現在はもっとインテリジェントな検知エンジンを搭載しており、UNION SELECTだけではブロックしません。
実は、私は5年前には、UNIONだけでもブロックしてよいのではないかと考えていました。というのも、通常の(特に日本語が使われている)ウェブサイトにおいて、ブラウザから「UNION」という文字列が送られてくるケースは非常に稀だろうと思っていたからです。
最近になって、ふと「実際にUNION SELECTが通常の文章の中でどのくらい使われているか、大量の英文のデータを処理してみたいな」と思い、情報収集を開始しました。するとまさにこの用途にぴったりのデータセットが見つかりました。Google BooksのNgram Viewerです。
Google Books Ngram Viewerを使う
上の図はUNION SELECTの登場回数です。1980年頃から急激に増えていますが、これは技術としてSQLが登場したタイミングと一致しています。つまりこの増加している分は、全てSQLとしてのUNION SELECTであると考えておそらく間違いないでしょう。
比較として、INSERT INTOを見てみます。
UNION SELECTと同じように1980年頃から急激な増加があります。急増しているのが大文字のINSERT SELECTであることからも、これがSQLであることは間違いないでしょう。
UNION SELECTは1980年以前は殆ど登場していませんが、INSERT INTOは1980年以前も一定の割合で使われていることがわかります。これはつまり、INSERT INTOという並びは通常の英文に比較的よく現れることを意味しており、INSERT INTOだけでブロックしてしまうと誤検知となる可能性がそれなりにあることになります。逆にUNION SELECTという文字列が見つかった場合、ベイズ的な発想では、それは殆どSQLインジェクションであると考えられます。誤検知である可能性は非常に低いので、特にインテリジェントな処理をせず、単純にクロと判定してしまってもおそらくWAFとして実用上は問題ないでしょう(よほど高い分類精度を求められる場合を除きます)。
ちなみにUNION SELECTとINSERT INTOの比(ともに大文字)は次のようになっています。
INSERT INTOの次の頻出単語を調べる
さて、WAFを使う(防御する)立場からすると、INSERT INTOという文字列を見つけたらブロックしてしまいたい気もしますが、先ほど見たように誤検知してしまう可能性が高いため、そういうわけにもいきません。何かよい考えはないでしょうか。そこで次の図を見てみましょう。
これは3gramのデータで、insert into fooとなるfooの部分の単語別に数を集計したものです。圧倒的にinsert into theという形で使われていることがわかります。
このGoogle Books Ngram Viewerのデータはこちらで公開されています。いわゆるパブリックデータセットです。
また、おそらく有志によってAmazon S3上に置かれており、こちらでも公開されています。こちらは少し古いバージョンのようです。Hadoopで処理することを前提としており、LZOで圧縮されたHadoopのシーケンシャルファイルになっています。圧縮された状態でファイルサイズが数十〜数百GBあり、レコード数は数億から数十億となっています。S3に置かれているため、そのままEMRなどから複数のサーバで並列で読み込み処理を行うことができます。HadoopやEMRに慣れていれば、データの規模が大きい割には、それなりに短い時間で処理が可能です。
AWS上のEMRを使い、お手軽にHiveとImpalaを利用して、このinsert into foo形式のデータを上位50位について集計してみたところ、次のような数になっていました(すべて小文字に統一して集計しています)。
+------------+-------+ | foo | count | +------------+-------+ | the | 18572 | | a | 2082 | | your | 969 | | it | 586 | | statement | 463 | | their | 412 | | this | 390 | | his | 368 | | an | 314 | | customers | 295 | | table | 284 | | [ | 280 | | . | 280 | | employee | 263 | | # | 238 | | orders | 232 | | employees | 205 | | its | 182 | | users | 181 | | our | 172 | | tablename | 146 | | each | 144 | | ( | 128 | | command | 124 | | her | 120 | | @ | 120 | | any | 118 | | table_name | 116 | | one | 107 | | and | 104 | | my | 97 | | bone | 96 | | them | 90 | | holy | 87 | | another | 85 | | that | 84 | | < | 74 | | or | 66 | | skin | 61 | | other | 60 | | these | 55 | | eq | 52 | | membranes | 47 | | such | 45 | | all | 43 | +------------+-------+
Ngram Viewer側には登場していないinsert into statementというパターンが存在しています。何かしらの理由でNgram Viewerには出てこないようです(データのバージョンの違いかもしれません)。
このように、INSERT INTOに続いてthe, a, your, it等が続いている場合を拾っていけば、INSERT INTOが正常に使われているケースの内の多くをカバーすることができます。つまりWAFのロジックとしてINSERT INTOに続いてtheやa等が続いていない場合にはブロックする、という方針も考えられます。
同じように、UNION SELECTやINSERT INTO以外でも、英文に頻出するパターンを元に誤検知を少なくする戦略が色々と考えられそうです。
まとめ
今回は、Googleが公開しているデータに基づき、SQLインジェクション検知を統計的なアプローチから考察してみました。フィードバック等あればお気軽に@kinyukaまでお寄せください。