postgres 9.3 でjson
postgres 9.3にはjsonがネィティブにサポートされている。json内の値をアクセスしたりインデックスできる。
psql (9.3.0)
Type "help" for help.# JSON型!
yoyodb=> CREATE TABLE publishers(id INT, info JSON);
CREATE TABLE# JSON型をインデックス!!
yoyodb=> CREATE INDEX ON publishers( ( info->>'name' ) ) ;
CREATE INDEXyoyodb=> insert into publishers (id,info) values (1, '{"name":"foo"}');
INSERT 0 1
yoyodb=> insert into publishers (id,info) values (2, '{"name":"bar"}');
INSERT 0 1
yoyodb=> insert into publishers (id,info) values (3, '{"name":"baz"}');
INSERT 0 1
yoyodb=> select * from publishers
yoyodb-> ;
id | info
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
1 | {"name":"foo"}
2 | {"name":"bar"}
3 | {"name":"baz"}
(3 rows)
# col->'key'でJSON内のフィールドをアクセス
yoyodb=> select info->'name' from publishers ;
?column?
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
"foo"
"bar"
"baz"
(3 rows)
yoyodb=> select info from publishers where info->>'name'='bar';
info
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
{"name":"bar"}
(1 row)
yoyodb=> select info->'name' from publishers where info->>'name'='bar';
?column?
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
"bar"
(1 row)
debianでのインストール
http://www.postgresql.org/download/linux/ubuntu/
echo 'deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main' | sudo tee
/etc/apt/sources.list.d/postgres.list
https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install postgresql-9.3
VIペダル
VIのモード切り替えを足でやって編集の高速化を可能にするペダルを自作したやつがいる:
https://github.com/alevchuk/vim-clutch
ペダルを踏むと「i」が入力され編集モードに。上げると「ESCAPE」でコマンドーモードに。素晴しいハックだ。
emacs用の「Controlペダル」が出たら使うかも。
被害妄想症の友人: Pythonでssh
paramikoというpythonのsshライブラリで遠隔マシンの操作が自動化できる。
hello paramiko
import paramiko
transport=paramiko.Transport( ( 'takao3' , 22 ) )
transport.connect(username='tengu', password='xxxx')
c=transport.open_session()
c.exec_command('ls hoge > /dev/null')
if c.recv_exit_status()==0:
print c.makefile('rb', -1).readlines()
else:
print c.makefile_stderr('rb', -1).readlines()
接続
pkeyを使うようにすべきだが、passwordを使わなきゃいけないときもある。ところで、TCPソケット以外のTransportって何がるんだろう…
transport=paramiko.Transport( ( 'takao3', 22 ) )
transport.connect(username='tengu', password='xxxx')
セッション・チャンネル
遠隔コマンドとはChannelと呼ばれるデータストリームでデータをやり取りする。チャンネルを開いてデータを書き込んだり、返答を読み出したり、プロセスの終了を待ったりexit statusを得たりできる。subprocessのPopenみたいな感覚だ。
http://www.lag.net/paramiko/docs/ (help(paramiko.Channel)) を参照。
# チャンネル(セッション)はコマンド毎に開く
c=transport.open_session()
c.exec_command('ls hoge > /dev/null')# コマンドが終了するまでブロックする。wait(2)に相当する。
if c.recv_exit_status()==0:
# 出力が少いのでバッファさせた出力を読む。
# 出力が多いと読んだ後にrecv_exit_status()しないといけないだろう。
print c.makefile('rb', -1).readlines()
else:
print c.makefile_stderr('rb', -1).readlines()
サイトのドキュメンテーション(http://www.lag.net/paramiko/docs/)もしっかりしていて、よく管理されたライブラリという印象が得られる。ちなみにparamikoという名は「被害妄想症の友人」という意味のエスペラント語の造語だそうだ。
Flameが世界最高水準の技術によるサイバー兵器であることを証明する機能リスト
f-secureがFlameの凄さを指摘している:
http://www.f-secure.com/weblog/archives/00002383.html
ユーザ監視
keyloggerとscreengrabberをもつ
フルテキスト監視
オフィス、PDF、Autodeskファイルなどのドキュメントをディスク・ネットワーク上で発見、テキストを抽出しそれをsqliteデータベースに保存。
盗聴機能
マイクロフォンをオンにして会話をオーディオファイルとして保存。
地域情報
ディスク・ネットワーク上で画像ファイルを探しそこからGPS情報を抽出。 写真がとられた場所を保存。
隔離されたマシンからも…
このように集められた情報は暗号化されたSQLiteデータベースとしてUSBスティックに保存され ネットワークのある環境に辿り着いたら送り返されるようになっている。ネットワークと接続されていないハイセキュリティー環境からも情報を盗み出せるようになっている。
...
証明書検証も打ち破る
- Microsoft Updateを傍受するproxyによりネットワーク内の他のマシンを感染。
- Microsoft Terminal Server license certificatesを悪用することにより偽のアップデートを捏造
- 独自のセキュリティー研究によりMD5ハッシュの衝突を作り出す方法を発見。これにより新型ウインドーズをも騙す偽certificateを作りだす。
上記の工作はスーパーコンピュータを使いこなすことが前提となる。このような高度な国家レベルのスパイ活動が2010年から行われていることになる。2010がサイバー戦争元年ということになる。
StuxnetとFlameの関係
Kasperskyの研究者がSuxnetとFlameの関連性を発見した
http://www.securelist.com/en/blog/208193568/Back_to_Stuxnet_the_missing_link
長々と証拠と解説が続くが最後の要約を見るとこういうことらしい:
- Flameはstuxnet以前にプラットフォームとして存在していた
- 初期(2009年版)のstuxnetはFlameのプラグインアーキテクチャによるモジュールを使用していた
- このモジュールはその時点で知られていなかったzero-day exploitにりよ特権エスカレーションを可能にした
- 2009年以降、stuxnetとFlameは別々に進化していった
つまり、協力関係にある二つのチームがサイバー兵器を開発していたということになる。
nginxで広告(HTML断片)をランダムに入れ替える
このようなHTMLで広告を表示するとしよう:
この画像リンクの部分をページロードする度に次のHTML断片の一つに入れ替えたい。
<div class="ad"><a href="..."><img src="..." /></a></div>
<a href="/redirect?dest=FOO"><img src="/img/FOO.png"></a>
<a href="/redirect?dest=BAR"><img src="/img/BAR.png"></a>
<a href="/redirect?dest=BAZ"><img src="/img/BAZ.png"></a>
高速化のためにキャッシュしておいたHTMLを、一部を書き換えるために再び生成するのは効率が悪い。HTMLの一部を前もって用意された幾つかのHTML断片の一つにおきかえるという簡単な操作なので、スクリプト言語によるバックエンドでなく、高速なCコードにやらせたい。幸いにnginxはこれを可能にしてくれる。
ssiとhttp_random_index_moduleを組み合わせれば、nginx内でページの一部をランダムに入れ替えることができる。
nginxをhttp_random_index_moduleを組み込んで構築する
./configure --with-http_random_index_modulessiはディフォルトで有効になっているので、ここで指定する必要はない。
random_index_moduleの設定
random_ads.conf
location /ad/banner/ { # このURLのリスポンスがランダムに入れ替わる。
random_index on;
alias /var/www/hoge/ad/html/banner/; # ここに表示するHTML断片ファイルを置いておく。
}
HTML断片管理
/var/www/hoge/ad/html/banner/にHTML断片を置く設定になっているが、そこにこのようにHTML断片ファイルを入れておく。ファイルの内容は上のHTML断面だ。
/ad/banner/からは foo.html, bar.html, baz.html のうちの一つの内容が返される。
html/banner/foo.html
html/banner/bar.html
html/banner/baz.html
この例ではHTML断片から参照される画像はこのように置いてある。nginx設定にこれに相当するalias文を入れておく。
img/banner/foo.jpg
img/banner/bar.jpg
img/banner/baz.jpg
nginx設定
- HTML断片を組込むURLのロケーションでssiを有効にする
location / {
...
ssi on;
...
HTMLにSSI文を入れる
<div class="ad"><!--# include virtual="/ad/banner/" --></div>
random index URLの作動を確認
何度もリクエストするとランダムに入れ替わるはず。
$ curl http://localhost:8000/ad/banner/
<a href="/redirect?dest=foo"><img src="/ad/img/banner/foo.jpg" /></a>
$ curl http://localhost:8000/ad/banner/
<a href="/redirect?dest=bar"><img src="/ad/img/banner/bar.jpg" /></a>
$ curl http://localhost:8000/ad/banner/
<a href="/redirect?dest=foo"><img src="/ad/img/banner/foo.jpg" /></a>
ページレベルでの確認
広告HTML断片がランダムに入れ替わっていることを確認。
$ curl -s http://localhost:8000/ | grep banner
<a href="/redirect?dest=foo"><img src="/ad/img/banner/foo.jpg" /></a>
$ curl -s http://localhost:8000/ | grep banner
<a href="/redirect?dest=foo"><img src="/ad/img/banner/foo.jpg" /></a>
$ curl -s http://localhost:8000/ | grep banner
<a href="/redirect?dest=bar"><img src="/ad/img/banner/bar.jpg" /></a>
結論
nginx+ssi+http_random_index_moduleで高速、効率的そして安定した広告ロテーションができるようになった。
背景
安く高速に多大なトラフィックを処理するウェブアプリの秘訣はとにかくスクリプト言語によるバックエンドをトラフィックに直接さらさないことだと思う。一般的にはmemcacheなどでこの問題を解決しているようだが、この方法は用いていない。単独サーバの設定だとファイルシステムが十分キャッシュの役割をはたす。あとキャッシュにおいてはリクエストを受けたページがないとバックエンドにクライアントが行くことになる。資源の乏しい環境ではこれが問題をおこす。(これについては後に詳しく書きたい) そこでバックエンドのウェブアプリはモデルの更新毎に静的なドキュメントをファイルシステムに書き込むようにしてある。それをnginxがクライアントに送る。つまり、ウェブアプリはリクエストに応えるサーバではなく、イベントに反応して静的なサイトを更新するdaemonとして機能している。アプリケーションとしてのウェブサービスでは無理だが、比較的安定したコンテンスを多くの人に見せる出版系サイトならこの手法が使える。
このように静的なファイルとして管理されたサイトで広告ローテーションを導入しようとした際にこのssi+http_random_index_module方をみつけた。せっかくnginxだけでページを送り返せるようにしたのに、広告の入れ替えのためにpython/djangoのような重いプロセスをその過程にかかわらせたくなかった。幸い同じような問題に直面した人がいたらしく、http_random_index_moduleがnginxの標準モジュールとして存在していた。