クラスタリングでアノマリ検知メモ

9月のSecMLでクラスタリングを使ったアノマリ検知をどうやっているか等について話をする関係で少し調べものをしていて見つけたネタをメモしておく。

オライリーのAdvanced analytics with SparkにKMeansでアノマリ検知をする章がある。以前に何となく読んではいたんだけど、結局最終的に何をもってクラスタリング結果と「アノマリかどうか」を結びつけているんだっけ?と思い読みなおした。

Now, we can make an actual anomaly detector. Anomaly detection amounts to measuring a new data point’s distance to its nearest centroid. If this distance exceeds some threshold, it is anomalous.

だそうで、「クラスタの中心からの距離がある閾値を超えたらアノマリだ」というごくシンプルな方法だった。

僕がやっているのはそもそもあるクラスタについては全部アノマリかもしれない、というシチュエーションである。そのため「そのクラスタに所属したらアノマリ」「むしろ中心に近かったら超アノマリ」みたいなことになるのでこの本のケースとは異なるな、とわかった。

メモおしまい。

Advertisements

「正義のハッカー、人工知能で異常検知」の難しさ

ふと脳裏に浮かんだのだが、これは実に難しい。

まず「正義」の定義が難しい。言うまでもなく、常に悪の側も「自分たちこそが正義だ」と主張するだろう。「アメリカこそテロ国家だ」みたいなやつである。正義ってなんだろう…と出だしでいきなりつまづくのである。

次に「ハッカー」。ハッカーではなくクラッカーと呼べ、みたいなのは最近見かけなくなった気がするが、我々は「ハッカー」の定義ではひと悶着せざるをえない。実に関わりたくない用語である。

そして流行りの人工知能。最近は書店に行くと中身のない人工知能本が溢れんばかりに平積みされていて気が滅入る。人工知能学会の中ですら人工知能の定義ができていないらしいので、我々が定義できるはずもない。というかそもそも知能の定義はされているのだろうか?

最後に異常検知。「これは問題ないのでは?」だって?甘いな…

まぁ、たしかに、用語としてはそこそこ定義しやすい。もちろん異常を検知するのだ。

しかし「異常」って何?という話になると、これは「正常ではないケースが異常」となるので、正常を定義する必要が出てくる。

セキュリティの文脈の異常検知(攻撃を見つけたい)だったりサーバのメトリクスの異常検知(主に時系列でCPU使用率等が夜間に突然上昇するようなやつを見つけたい)だったり、人や場面によってそれぞれの「正常」があまりにもバラバラなので、異常検知の意味するところもバラバラになる。

「異常検知に興味があるひと」を集めて議論させても、おそらく何も生まれないだろう。「異常検知」という用語は意味が広すぎるのだ。

まさにカオスである。助けて、正義のハッカー!!

 


PostgreSQLでのSQLインジェクションでシステムコマンド実行

https://www.postgresql.org/docs/9.3/static/sql-copy.html

今朝気づいたが、バージョン9.3以降では、COPYコマンド経由(PROGRAM)で外部コマンドを簡単に起動できる。xp_cmdshellの亡霊が再び…なんちゃって…


セッションIDをCSRFトークンに使うべきでない理由

malaさんも2年程前に書かれているのですが、未だに国内のCSRF対策の解説で「セッションIDをCSRFトークンとして使う」というアイデアが披露されていて辟易します。

喩え話は好きでないですが、「複数のサイトで同じパスワードを使っていたら一箇所から漏洩し、パスワードリスト攻撃を受けた」というのを彷彿します。セッションIDとCSRFトークンは単純に別の値にした方がいいです。

さてこのエントリの本題はここからで、CSRFトークンよりもむしろセッションIDの方です。最近は443番ポートへクロスサイトでリクエストを大量に送らせてそれをキャプチャし、すべてのリクエストに共通して含まれてくるCookie中のセッションIDを解読するBEAST/CRIME系の攻撃が知られるようになりました。

これらは基本的にはTLS/SSLの問題でありそれぞれ個別に対策が存在しているものの、基本的には「セッションIDがずっと同じ値である」という部分、HTTP特有の仕組みを攻撃対象としています。(攻撃対象がBasic認証などの場合はこの限りではないです)

これを受けて「何千もリクエストが勝手に送られている間、セッションIDがずっと同じなのって間抜けだよね?」と考えるのがまともな感覚だと思うのですが、いかがでしょうか。つまりセッションIDがずっと同じであるという実装の常識をそろそろ変えていくべきだと思います。あくまで保険的な対策となると思いますが、今後登場するかもしれないBEAST/CRIMEの発展形を防ぐ可能性が高いと考えます。

一部、セッション固定により「ログインしたタイミングでセッションIDを変える」ということは良く知られており実践されていますが、そもそもセッションIDはコロコロ変えるべきなのです。

さて話はCSRFトークンに戻りますが、セッションIDの値をそのままCSRFトークンとして使ってしまっていると、上記のように「セッションIDを頻繁に変更する」ということができなくなってしまいます。なのでセッションIDの値をCSRFトークンにするのはやめましょう。

「…やめましょう」とか書きましたが、別の件(CSRFトークン インタビューズ)でシェアの高いいくつかのフレームワークについて調べてみたところ、そもそもセッションIDの値をそのままCSRFトークンにしているものをひとつも見つけることができませんでした。もし見つけたら教えてください。

なんか、ガラパゴス的な議論をしていたようで脱力します。


非線形データに普通のKMeansを使う

1,2,2,2,3,3,4,10,10,11,11,11,12,12,12,12,13,13,25,25,26,26,26,27,28,28,29,29,29,29,30,30,30,31

例えば上記のような1次元のデータがある場合を考える。ある小学校のクラスで行われた簡易テストの点数のようなイメージだ。「1点の生徒が1人、2点の生徒が3人・・・31点を取った生徒が1人」という感じである。

nonlinear2

ヒストグラムは上記のようになる。ここで色分けは意図的に行っている。

  • 赤は落ちこぼれ
  • 緑は普通の生徒
  • 黒はよくできるグループ

のように、いわゆるラベル分けを行うことができる。繰り返しになってしつこいが、これは意図的なラベル分けだ。

ここでは3つに分類すると決めており、データは人間から見ると自然に3つに(ヒストグラム上で)別れている。各グループ間は線形分離が可能だ。

このような場合、KMeansクラスタリングでk=3とすると完璧にクラスタリングしてくれる(ことが多い)。「ラベルが3種類だから、k=3とする」というごくありがちなアプローチである。

a <-c(1,2,2,2,3,3,4,10,10,11,11,11,12,12,12,12,13,13,25,25,26,26,26,27,28,28,29,29,29,29,30,30,30,31) 
> kmeans(a,3)
K-means clustering with 3 clusters of sizes 16, 11, 7

Cluster means:
[,1]
1 28.000000
2 11.545455
3 2.428571

Clustering vector:
[1] 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Within cluster sum of squares by cluster:
[1] 56.000000 10.727273 5.714286
(between_SS / total_SS = 98.1 %)

Available components:

[1] "cluster" "centers" "totss" "withinss" "tot.withinss"
[6] "betweenss" "size" "iter" "ifault"

仮に今回のケースが、ラベル有りで上記データが提供されていて、KMeansでモデルを作り、新たなデータを「落ちこぼれ」「普通」「よくできる」のいずれかに分類したいという状況だとする。この場合、データが上記kmeansの実行で得られたクラスタ中心(28, 11.5, 2.4)のどれに一番近いか?を判断するだけで良い。

しかし、ラベルが3種類ではなく、下記の2種類だったらどうなるだろうか。

nonlinear3

ここでラベルが以下の2つであるとする。

  • 緑は「普通でない生徒」
  • 赤は「普通の生徒」

突如、緑に属するデータは非線形な集まりとなってしまう。先ほどと同じようにKMeansでモデルを作り、新たなデータを分類する問題として考える場合、先ほどと同じアプローチで「ラベルが2種類だからk=2でクラスタリングしよう」と思っても当然うまくいかない。

ここで「くそっ、KMeansは非線形データに弱いんだぜ…」と考えてカーネル関数とかそっちに走るのもひとつの手だが、もっと超簡単な方法がある。というかこのブログエントリを先頭から読めば自然に気づくと思うが、「ラベルが2種類だからk=2」というのを「ラベルは2種類だけどk=3でやってみよう」とするだけである。

そして、実際の分類の際には

  • 1つめのクラスタ中心に近ければ「普通でない生徒」
  • 2つめのクラスタ中心に近ければ「普通の生徒」
  • 3つめのクラスタ中心に近ければ「普通でない生徒」

というロジックに従えばOKである。

クラスタリング結果をそのまま分類に使うのではなく、クラスタリング結果にもうひとつだけ処理を追加するだけでよい。クラスタリングはあくまでも数値処理で、人間がそれをうまく解釈してやるだけの話だ。

あまりにも簡単な話なのだが、意外と目にしない(私の探し方が悪いだけかもしれないが)ので、ブログに書いてみた。


自宅で働くJavaプログラマになって13年経過したのでメモ

当時は「SOHO」というキーワードで知られている、いわゆる在宅勤務。私は2002年頃からずっとやっていて…
まぁ誰かの参考になる可能性もあるかと思ってメモします。

まず、私の在宅勤務がどんなものかを簡単に。

私は2002年頃に「株式会社ビットフォレスト」というスタートアップを立ち上げた、いわゆるファウンダーです。そのため、世の中の人が「在宅勤務」で想像するであろう「雇われている」形態ではありません。ここは非常に大きなポイントになると思います(要するに自分がさぼると、きっちりツケが廻ってくるという意味で)。

場所は横浜市の南の方で、「下永谷」という名前の、駅前に何もない場所でやっています。最近、ついに駅前にコンビニが出来ました。どうでもいい。
在宅勤務を始めるよりも前に結婚しており、一人暮らしではありません。

会社のオフィスは、立ち上げた当時は存在せず、全メンバーが在宅勤務でしたが、数年後に四谷三丁目にオフィスを構えました。現在は在宅勤務しているメンバーは私を含め数名いますが、多くはオフィスで仕事をしています。

仕事の内容はソフトウェア(あるいはウェブサービス)の開発で、2002年頃からずっとJavaを使っています。なので、勤務時間中、殆どの時間はコードを書いていることになります。

なぜ在宅勤務にしたか?

大きく4つ理由があり、

  • オフィスでなくても仕事ができる(オフィスのコストの削減が可能)
  • 満員電車が苦痛
  • 通勤時間がもったいない
  • 集中できる

というものです。特に説明しなくてもよいですね。(1つめについては、その後結局オフィスを構えてしまいましたが・・・)

さて実際にやってみた感じは次の通りです。

むちゃくちゃ集中できる

仕事をしている時間は、同居している家族はそれぞれ仕事や学校で出払っていることが多いため、自宅にはひとりという状態になります。
場所が住宅地で、外も静かなため、数時間続けて集中してコードを書くことができます。

途中誰かから話しかけることがなく、また電話が鳴ることも殆どないため、プログラマにとっては理想的な作業環境です。非常に生産性が高く、また基本的に毎日そのような環境で仕事を継続的に行うことができます。

数年間でのトータルのアウトプット量で考えた場合、かつてサラリーマンとしてオフィスに通勤していた頃よりもはるかによい結果が出せていることは間違いないと思います。この点については今振り返ってみて、本当によい選択(時間を無駄にしなかったという意味で)だった思います。

ストレスが少ない

部屋に連続して数時間以上一人でいるという状態は、非常にストレスが少なく済みます。他の人の音やしゃべり声、ニオイなどがないので、心が乱されることがありません。また、例えばウ○コしたくなったらすぐトイレですればよいだけです。例えば下痢をしている日には、15分おきにトイレに入っても何も問題ありません。オフィスの場合、15分おきにトイレにいくのって結構周りの目が気になってつらいですよね。そういう生理的な欲求などを我慢する必要がない点についても、在宅勤務は優れていると思います。

自己管理が要求される

誰もいないので、誰も注意してくれません。私は太ってはいませんが、例えば異常な量のお菓子をバリバリ食べていても、誰も「食べ過ぎじゃない?」と言ってくれません。そのため食欲をはじめ、色々な面で自らの堕落を自ら節する必要があります。自己管理が苦手な人は在宅勤務は向いていません。

さみしいか?

在宅勤務のデメリットとして「寂しさ」が挙げられるケースがありますが、私は幸い家族がいることもあり、その点を感じたことはありません。在宅勤務の後は呑みに行く仲間はいないので、頻繁に仲間と呑みに行きたい人には辛いかもしれません。

どんな職業に向いているか

プログラマーのように、コンピュータだけあれば完結するような仕事が向いていることは言わずもがなです。他には、その人が雇われているのか、自営なのかが大きなポイントだと思います。自営の場合にはピーク時には頑張って稼ぎ、それを過ぎたら休みを増やしてのんびりすることもやりやすいですし、さぼると自分の収入が少なくなるため自制もやりやすい面があるでしょう。

また、在宅勤務には「面白い」と思える仕事が向いていると思います。

働きすぎる

37signalsの本にありましたが、在宅勤務で注意が必要なのは「さぼること」ではなく「働きすぎること」ですw。

朝食を済ませたらコーヒーを淹れて即仕事が開始できますし、また夜も仕事を終えたら10分で眠れてしまうため、どうしても仕事をしすぎになります。私の場合、コードを書くことは仕事でもあり趣味でもあるため、この点については我ながらダメだなと思います。

以上、誰かの参考になれば。


コモディティサーバ戦略のパラドックス

servers

今さら確認するまでもないが、サービスの成長に合わせてこまめにサーバリソースを追加し、負荷をうまく分散して処理していく戦略がスケールアウトで、図の上がこれを示す。
主に安価なコモディティサーバを使うイメージである。

一方、図の下は、最初から高価で高性能のサーバを買ってしまい、それをぎりぎりまで使い切って、あるタイミングでまた高性能のサーバを追加するイメージである。まぁ、一昔前まで当たり前だと考えられていたアプローチである。

上だと最終的に6台のサーバが、下だと最終的に2台のサーバがある感じである。

図中の青い部分が「買ってしまったけど使っていない」リソースであって、無駄なコストである。

上の方が、青い部分の面積は小さく、無駄なコストを省くことに成功している。スケールアウト戦略を選択する理由にはいくつかあるが、そのうちでポピュラーなものがこの「無駄なコストの削減」である。

しかしこのときサーバ台数は増えてしまっているので、DatadogやMackerelのような「サーバ毎に課金される」サービスを利用する場合には、料金もきれいにスケールしてしまう。

貧者の戦略としてコモディティサーバを選んだのに、価格が高くなってしまうのだ。

でもまぁ、台数が増えたらサーバ管理の手間は増えるから、「サーバ管理を助けるサービス」の使用料が高くなるのは当たり前だよ、って言われると納得するかも…