HOKKE-19に登壇,参加してきた

久々の日記ですが・・北海道から編集をかけると言う.

11月28日,29日に開催されたHOKKE-19に参加してきました.2つの研究会が毎年北海道で合同開催している学会です.

ARC
計算機アーキテクチャの研究会
HPC
ハイパフォーマンスコンピューティング研究会

研究室の同期と指導教員の先生の3人で参加してきました.

続きを読む

puttygenに暗号化されたOpenSSH鍵をインポートしようとするとエラーが出る

パスフレーズで暗号化されたOpenSSH鍵を,PuTTYWinSCPに同梱されているputtygenを使って,PuTTYの鍵に変換しようとするとエラーが出ました.

エラーは以下のとおりです.

PuTTYgen Error
秘密鍵を読み込めませんでした。(ciphers other than DES-EDE3-CBC not supported)
続きを読む

yi.orgを(ez-ipupdateの代わりに)wgetで更新する

yi.orgって?

DDNSサービスの有名なところに、yi.orgというサービスがあります。DDNSとはDynamic DNSの略で、IPアドレスが固定でないホストでも、DNSが返すIPアドレスを動的に変化させることで、ドメインネームを使えるようにしましょうというものです。

yi.orgのウェブサイトではUNIX系のサーバからIPアドレスを更新するには、ez-ipupdateというクライアントを使いましょうと書いてあります。このクライアントは、yi.orgがサポートしているプロトコルのうち、「GnuDIP2」というプロトコルを用いて更新します。

ところが最近、公式ページの「Help」に書かれている設定どおりでも、ez-ipupdateが「Invalid login」とエラーを吐いて、IPアドレスを更新できなくなっていました。

yi.orgのIPアドレス更新用プロトコル

私はWindowsではDiCEというDDNSクライアントのユーザなので、こちらの更新スクリプトを見てみると、どうやらGnuDIP2プロトコルを使わずに更新しているように見受けられます。

実はyi.orgがサポートするプロトコルは1つではなく、それについては以下のページで述べられています。
http://www.yi.org/help/tech/protocols.shtml

そのうちの「MonoLith (ml.org)」と書かれているプロトコルは、Basic認証を使って指定されたURLにアクセスするだけという簡単な方法で更新できます。ただし、このプロトコルでは、パスワードを安全な方法では送信しない(ほぼ平文で送信され、盗聴されると読めてしまう)ので、注意が必要です。

wgetで実現

先に述べた「MonoLith」プロトコルを、Unix系の環境でほぼ標準で使える?はずの、簡易HTTPクライアント「wget」でやってみました。具体的には、以下を実行します。

$ wget -q --http-user=[更新したいドメイン名] --http-password=[アカウントのパスワード] --spider http://www.yi.org/bin/dyndns.fcgi

すっげぇ簡単ですね。

説明しよう。wgetコマンドとはhttpプロトコルでファイルをダウンロードして保存するためのCUIプログラムである。--http-userと--http-passwordはBasic認証のユーザとパスワードを指定するオプションである。--spiderはファイルを保存しないようにするオプションである。-qはもちろん--quiet。--spiderがミソで、GETリクエストを発行するだけのプログラムに大変身させることができる。

これをファイルに保存して、起動時に実行されるように設置すれば良いでしょう。ただし、パスワードを直で書かないといけないので、独立したファイルに書き出しておき、所有ユーザ・グループを両方rootにし、パーミッションを所有ユーザのみの読み書き実行(700)にしておくべきでしょう。その場合は、shebangを忘れずに、以下のようなファイルを作成してください(今回は便宜的にファイル名をupdate_yi_org.shとしておきます)。

#!/bin/sh
wget -q --http-user=(更新したいドメイン名) --http-password=(アカウントのパスワード) --spider http://www.yi.org/bin/dyndns.fcgi

以下(のようなコマンド)を忘れずに・・。パスワードが盗まれないように、セキュリティ対策をしましょう。

# chown root:root update_yi_org.sh (root権限でファイルを作成した場合はこっちは不要)
# chmod 700 update_yi_org.sh

起動時にスクリプトを実行させる(PPPoEではない場合用)

起動時に実行させるには、ネットワークインタフェースの開始時にスクリプトが実行されるように、ネットワークの設定を変更するとよいでしょう。

Ubuntuを含むDebian

/etc/network/interfacesの、該当するiface行の後に、以下のような行を追加します。

up /path/to/update_yi_org.sh
CentOSFedoraを含むRedHat

/etc/sysconfig/network-scripts/ifup-postの最後に書いてあって見つけたけど、こんなんわかるかよ・w・;。/sbin/ifup-localというファイルを作成しておけば、そのファイルがインタフェースの開始後に呼び出されて、その引数はデバイス名らしい。というわけで、以下のようなスクリプトを/sbin/ifup-localというファイル名で(root権限で)保存し、実行権限を付与(「chmod +x /sbin/ifup-local」)します。

#!/bin/sh
if [[ "$1" = "(インタフェース名、eth0など)" ]]; then
	/path/to/update_yi_org.sh
fi

または、「http://jfut.integ.jp/2007/02/25/rhel-and-entos-network-config-for-lvs-keepalived-vrrp-dsr/」で述べられているように、symlinkを作成します。具体的には、上記のスクリプトを(実行権限を付与してユーザもグループもrootの)ファイルに保存し、/sbin/ifup-localというファイル名で、当該スクリプトを保存したファイルに対するsymlinkを作成します(/sbin/ifup-local→update_yi_org.sh)。
ちなみにif文を書かないとlo(ループバックインタフェース)が開始されたタイミングで起動されるなど、不必要なタイミングで起動されてややこしいことになるかもしれません。

Gentoo

以下のようなシェルスクリプトを、/etc/conf.d/netに追加します。詳しくは/etc/conf.d/net.exampleを参照してください。

postup() {
	if [[ "${IFACE}" = "(インタフェース名、eth0など)" ]]; then
		/path/to/update_yi_org.sh
	fi
}

PPPoE環境の人はここから重要!!

PPPoEを使っている場合、前述のような方法で、インタフェースの開始に合わせてスクリプトを実行するだけでは、上手くいかないかもしれません。なぜならば、インタフェースの起動スクリプト自体は「開始」状態になっていても、実はまだPPPoEセッションが開始されていなかったり、自動的に再接続してIPアドレスが変化していたりするかもしれません。PPPoEセッションが開始されたタイミングに必ずスクリプトが実行されるべきなのですが、実際は(起動スクリプトからはそのことが分からないため)実行されるようになっていない可能性が高いです。

pppdを使っている場合(当該ホストからPPPoEセッションを張っている場合は主にこれ?)

pppdを用いてPPPoE接続を行っている環境の場合、pppdの設定として設置すると、PPPoEセッション開始後に自動的に実行されるようになります。なお、恐らく再接続時にも実行されると思います。

具体的には、/etc/ppp/ip-up.localというファイルを使います。存在しなければroot権限で作成し実行権限を付与(「chmod +x」)しておきます。そこに、update_yi_org.shを呼び出す行(「/path/to/update_yi_org.sh」)を追加します。

/etc/ppp/ip-up.localがそもそも存在しない場合は、update_yi_org.shを/etc/ppp/ip-up.localとして作成しても良いでしょう(もちろんこの場合は所有権やパーミッションに注意)。

ルータ側でPPPoEを設定している場合

ルータ側のIPアドレスが更新されたことを検知するには、定期的にIPアドレスをチェックするぐらいしか方法がないでしょう。http://checkip.dyndns.org/などでチェックしてみて、もしIPアドレスが変化していたら更新というのが正しいのですが、これについては面倒になりそうなので、今日は割愛します。

Firesheep問題への対応方法,セッション鍵をハッシュ関数+Saltでワンタイムパス化.

とりあえずは暫定で書いてみよう.
この対策はJavaScriptが使える環境でないと無理な上に,うまく実装しないときっとバグるし,現実的かはわからない.
でもきっと全部SSLになったらそれはそれでコストがしんどいもんね.
あそうかCookieのとなりにセッション鍵管理のプロトコル仕様・・・(ry.


セッション鍵が盗まれるとあっという間にパクられる.→セッション鍵を盗まれなければいい,か,セッション鍵がワンタイムであればいい


どういうことか.


学校の講義で出てきたワンタイムパスワード「S/Key」方式を思い出した.これは,元のパスワードを99回とかの多い回数でハッシュ関数にかけた暗号化パスと,その回数を(初期化時に)サーバ側に送信し,手元に元のパスワードを保存しておく.サーバは保存してある暗号化パスよりも,ハッシュ関数が1回少ない暗号化パスを送れとクライアントに要求し,クライアントは元のパスワードをサーバから指示された回数だけハッシュ関数にかけて送信する.サーバは,送られてきた暗号化パスにさらに1回ハッシュ関数をかけて,保存されている暗号化パスと比較し,同じであれば認証し,送られてきた暗号化パスとそのハッシュ回数を保存し,元の暗号化パスは捨てる.
http://okaweb.ec.kyushu-u.ac.jp/lectures/ds/98-Reports/tumura.html


まぁ,この最初のパスそのものをネットワークに送信しないって言うのや,ハッシュ関数に99回もかけるとかいうのは,やりすぎってことで・・・.


簡単にいくと,最初のSSL通信で,あらかじめセッションID,Salt(乱数)を共有しておく.SSL保護からはずれた後,サーバは次のリクエストの際に,前のセッション鍵+Saltのデータに1回ハッシュ関数をかけた値を,そのセッションIDに対応するセッション鍵として期待しておく.クライアントはJavaScriptを使って,リクエスト送信直前,またはレスポンス受信直後(こっちはキャッシュとかもあるし可能なの!?)に,次のセッション鍵を計算してCookieに格納しておく.次回のアクセスの際には,そのセッション鍵が用いられる.これによってセッション鍵を,Saltという共有知識を使って,ワンタイムパス化することができるのでは.


1回目のセッション鍵はSaltに1回ハッシュ関数をかけただけのものが使われるかもしれないけど,(その辺もし危険だったとしたら)必要に応じて乱数+Saltとかにすればよいと思う.また,サーバとクライアントでハッシュ回数の同期がとれないかもな問題に関しては,サーバ側の方が多くハッシュを行っているのはまぁ普通おかしいのでエラーにするとして,クライアント側からハッシュしたトータル回数をリクエスト時に送信して,もしサーバ側のほうが少ない回数だったらそれに追いつくようがんばってサーバが計算するようにする.あまりにも大きい回数を指定されるとDoS攻撃になるかもしれないので,許容範囲を決めておき,同期されてなさが度を越えている場合はエラーにすればよい.


というのが私が考えた対策.わかりづらいとか,それではダメっぽいというのは意見をください・w・!


ん?まてよ・・・そういえば,Cookie以外の「サーバに決して送信されない」Saltのためのストレージが存在しない気がする・・・;w;

Lightwave3DのLWOB(古い版)読み込み関係のfixと、断念したLWO2読み込みの実装

もう3ヶ月ほど前の話ですが、拡張現実(AR)のプログラムを学祭で出そうということで、NyARToolkitとJava3Dを使って実現したのですが、その時、Lightwave3Dを使ってモデルデータを作成してもらっていたので、これをいかに読み込むか考えていました。
ところが残念ながら、Java3D標準のLightwave3Dファイル読み込み機能は、なんと10年?ほど前のLWOBフォーマットのみにしか対応していなかったのです。
もうこのフォーマットは廃れていて、どこでも使われていないようでした。
そこで、LWO2フォーマットの読み込みをできるように、ソースを拾ってきて改良していたわけなのですが、サブパッチの読み込みあたりで、知識と技量が足りず断念しました。


ちなみに結局は、Metasequoiaで読み込んで.mqoで保存して、それをJava3D用.mqoローダを配布してくれている人のサイトからお借りしてロードする、という流れでした。
http://kurusugawa.jp/2007/07/17/java3d%E3%81%A7metasequoia%E3%81%AE%E3%83%A2%E3%83%87%E3%83%ABmqo%E3%82%92%E3%83%AD%E3%83%BC%E3%83%89%E3%81%99%E3%82%8B/


なんか同意書にサインする必要があるとかで、LWOB読み込みに関するパッチを(面倒があって)投げれていない分と、LWO2に途中までとりかかったコードを、とりあえずgithubにぶち込みました。元のソースはBSDですが、私の部分はパブリックドメイン扱いにしておくので、LWOBのfixをJava3Dプロジェクトに送ってくれる人や、LWO2を引き継いでくれる人が入れば、他力本願で申し訳ないのですが使ってください、ということにしておきます。
https://github.com/ypresto/java3d_lw3dloader

CSRFProtectionを有効にしていると、CSRF attack detectedになり続ける問題

Symfonyのformで、悪名高き(?)_csrf_tokenを有効にしていると、ブラウザの「戻る」ボタンを押した途端に悪夢が始まってしまうようだ。
どういう事かというと、_csrf_tokenがinvalidだろうがnullだろうが、送られてきた値をそのまま返すようなのだ。ということは、一度でもinvalidなtokenを送ってしまうと、もう無限loopに捕まってしまうというわけだ。
問題は、token自体は毎回生成はされているのに、$this->form->bind()が実行されると、出力する際に受け取った値しか出力しないということ。そこで、受け取った値に関わらず、_csrf_tokenを更新するパッチを書いてみた。が、何か問題があると指摘されそう。例えば、無駄にtokenを生成しすぎだとか、実はワンタイムトークンではないとか、2回submitを実行すれば(1回目で_csrf_tokenが再生成されて)submitできるのは仕様??とか。やや荒療治な感じなので悪しからず。


以下がpatch付きticketのページ。
http://trac.symfony-project.org/ticket/9299


とりあえずは、ログインページや検索ページでは、CSRFProtectionを無効にすべきかもしれない。送信してもまた同じページに戻ってくる場合(検索フォームとか。多分sfFormはこの使われ方を想定していないから今回みたいな問題があるのだと。)のうち、そこにあるのがupdateなCSRFを対策したいformの場合(チャットとか)は、このパッチが必要ではないかと思うのです。