Tuesday, April 22, 2014

[perl][memo] File::Tempのバッドノウハウ

■まとめ
  • tempfile(...)が作成したテンポラリファイルは、環境によってはflockされていることがある
  • tempfile(CLEANUP => 1)は、テンポラリファイルへの参照をretainする
  • つまり、CLEANUPを指定している場合、参照カウントに頼った自動closeは機能しないので、明示的にcloseする必要がある
  • また、明示的にcloseしないとflock可能にならない場合がある

■ログ
16:23:30 <kazuho_> あれ perl って file handle への refcnt がゼロになったら自動的に close してくれますよね
16:23:43 <tokuhirom> してくれますね
16:23:48 <tokuhirom> しなきゃおかしいw
16:32:33 <kazuho_> https://gist.github.com/kazuho/11168660
16:32:37 <kazuho_> こういうことだった
16:32:53 <tokuhirom> あー。それな。
16:33:01 <tokuhirom> なんか File::Temp さんごちゃごちゃやってんすよね
16:42:37 <kazuho_> linux で perl -MFile::Temp=tempfile -e '(undef, my $fn) = tempfile(UNLINK => 1); sleep 100'
16:42:47 <kazuho_> ってやっても、テンポラリファイルが開きっぱになるなー
16:49:41 <kazuho_> _deferred_unlink って関数が $fh にぎにぎしちゃうのかー > File::Temp
16:50:50 <tokuhirom> UNLINK => 1 するとなかなか UNLINK されなくなるの、だいぶアレゲですねw
16:51:16 <kazuho_> というより、
16:51:22 <kazuho_> > # close the filehandle without checking its state
16:51:23 <kazuho_> > # in order to make real sure that this is closed
16:51:30 <kazuho_> という理由で $fh をにぎりっぱにしてるから
16:51:38 <kazuho_> refcnt 減らしても自動でcloseされない
16:52:13 <tokuhirom> なんか UNLINK => 0 してやり過ごすってのを昔見た気がした
16:52:27 <kazuho_> そしたら自動削除してくれないじゃんw
16:52:33 <kazuho_> 明示的にcloseするわ…
16:53:03 <kazuho_> Starlet で select を、テンポラリファイルの flock で囲おうとしてるんだけど
16:53:15 <kazuho_> osx だと tempfile が EXLOCK 指定する
16:53:23 <kazuho_> → UNLINK してるとファイル開いたままになる
16:53:28 <kazuho_> → ロックできない!!!
16:53:34 <kazuho_> という問題なので
16:54:01 <tokuhirom> 明示的にクローズが正解かー
16:54:07 <kazuho_> ですね
16:54:09 <kazuho_> まあ、UNLINK => 1 してるとファイル開きっぱになるの、バグだと思うけどなー
16:54:15 <kazuho_> file descriptorたりなくなるじゃん!!
16:54:52 <kazuho_> まあそういう場合は tempdir してその中に手動でファイル作ろうね、なんだろうな
16:54:53 <tokuhirom> なんかでもそこ今更変えられなさそうw
16:54:57 <kazuho_> 変えようがないでしょうね
16:54:58 <tokuhirom> a-
16:55:40 <kazuho_> あざますあざます

Friday, April 11, 2014

[メモ] Starlet 0.22のリリースに伴いThundering Herd問題を再訪した件

@takezawaさんから、PerlベースのWebアプリケーションサーバであるStarletで複数ポートをlistenできるようにするPRをいただいたのでマージしました。やったね!

で、それに伴いprefork型TCPサーバのThundering Herd問題を再訪したので、その備忘録。なお、Thundering Herd問題については、prefork サーバーと thundering herd 問題 - naoyaのはてなダイアリーや、Starman と Starlet のベンチマークと Accept Serialization - Hateburo: kazeburo hatenablogあたりを参照のこと。

まず、こんなテストスクリプトを書いた: thundering-herd.pl

こいつを書いてあるコメントのとおり実行してみることで、2種類のケースでThundering Herd問題が存在するか調べることができる。

で、こいつを使った結果、以下の結論に達した。
  • accept(2)の呼出によるThundering Herd問題だが、多くの環境で過去の問題になったと考えてよい
  • select(2)で接続を待ち受け、次にaccept(2)を呼ぶようなケースでは、依然としてThundering Herd問題が存在する(当然と言えば当然だが)
とか言ってみたけど、、linux 2.6.32とOS X 10.8.5でしかテストしてないので、補足あれば教えてください m(__)m

あと、複数のポートにbind(2)するTCPサーバを書く際に注意すべき点として、prefork型サーバでselect(2)accept(2)の呼出順序で接続を確立する際は、ソケットをnonblockingモードにしておかないと、ワーカプロセスが余っているのに接続できないといった事態が発生する可能性がある。

この点は、上記のテストスクリプトを書くまでレビューするのを忘れていたんだけど、確認したらtakezawaさんのコードではちゃんと記述されていて、ちょっと感動した。いい仕事ありがとうございました。

Heartbleed脆弱性と、その背後にあるWebアプリケーションアーキテクチャの一般的欠陥について

■Heartbleedのリスクと善後策

Heartbleedは、攻撃者が一定の条件を満たすOpenSSLが動作しているサーバの、任意位置のメモリを外部から読み出すことができてしまうという脆弱性です。具体的には、以下のようなリスクが想定されています。

  • 秘密鍵の漏洩による、偽サイトの出現(あるいは中間者攻撃)
  • 秘密鍵の漏洩により、(過去のものを含む)パケットキャプチャの解読
  • サーバの同一プロセスが行った処理に関連する(他のユーザーのパスワードやセッションキーを含む)データの漏洩

漏洩した秘密鍵を用いた攻撃には、ユーザーを偽サイトへ誘導できたり、パケットの経由点を管理しているなどの、経路上の要件が必要になります。他のユーザーのデータの漏洩については、経路上の要件は不要な一方、攻撃の実施に近いタイミングでサーバにアクセスしたユーザーのデータしか漏れない、という違いがあります。

どこまで対策を施すべきかは、攻撃を受けた可能性をどの程度と評価するか、個々の組織の判断によるところがあると思うのでコメントしませんが、以下のような対策が必要になる可能性があります。

  • 偽サイトの出現や中間者攻撃、これからのパケット解読を防ぐには、新しい秘密鍵/公開鍵ペアを使うサーバ証明書への更新と、現行のサーバ証明書のrevocation
  • 秘密鍵の漏洩によって過去のパケット解読が容易になることのないよう、Forward Secrecyを満たすようなサーバ設定
  • 他のユーザーのものを含むデータの漏洩については、セッション情報のリセットとパスワードの再設定のお願い

■Heartbleedの背景

Heartbleedのような問題は、そもそもなぜ発生するのでしょう。それは言うまでもなく、安全性の根拠をプログラムが正しく記述されることに求めているからです(つまり、プログラムにバグがあると脆弱性として発現する可能性があるから)。最小権限の原則が守られていない、と言い換えてもよいと思います。

Heartbleedにおいて他のユーザーのデータが漏洩するのは、一つのプロセスが複数のユーザーの通信を処理しているからです。ユーザーごとに(あるいは接続毎に)別個のプロセスを割り当てていれば、他のユーザーの通信内容が漏洩することは起こりえません。

秘密鍵の漏洩にしても、秘密鍵を必要とする処理(TLSのハンドシェイク中の一部処理に限られます)と、TLS Heartbeatの処理(ハンドシェイク中以外に限られます)を別個の権限の元で動作させていれば、発生しなかったと言えます(17:19修正)。

多くのOSのプロセス分離やファイルアクセス権の制御に見られるように、最小権限の原則に基づいたセキュリティは有効に機能することが知られています。

にもかかわらず、ウェブ関連のソフトウェアにおいては同原則を用いずに、安全性の根拠をプログラムにバグがない点に求めるという悪しき慣習が続いています。特に、機能別の権限分離はまだしも、アクセスユーザー別の権限分離については系統だった実施例が非常に少ないという印象をもっています。

たとえば、SQL Injectionに代表されるSQL関連の情報漏洩も、アクセス制御にRDBMSのアクセス制御機構を用いず、アプリケーションプログラム内のSQL(とそのエスケープ)が正しく記述されている点に、安全性の根拠を求めているが故に発生しているわけです注1

ウェブの黎明期においては、(小数のユーザが使用することが一般的だった)RDBMSの認証システムの要件と多数が使用するウェブの要件は異なるのでRDBMSの認証システムはウェブ向けには使用できない、というのは説得力のある言い訳でした。ですが、今やRDBMSの用途の多くがウェブアプリケーションのデータストアになっているはずです。にもかかわらず、RDBMS(あるいはその他のデータストア)のアクセス制御機構をウェブアプリケーションからのアクセス制御に使う、というのは一般的な手法になっていません。

同様の問題はウェブアプリケーションサーバにもあり、複数のユーザーのリクエストを単一のプロセスで処理する結果、情報漏洩が発生するケースが見受けられます注2

リバースプロキシ、アプリケーションサーバ、データストア、そういったウェブアプリケーションの各要素について、最小権限の原則に基づいた、アプリケーションにバグがあっても脆弱にならないようなアーキテクチャの構成技法と技術開発が求められているのではないでしょうか。


注1: 強制アクセス制御がうまく機能しないようなアクセスパターンも、もちろん存在します
注2: 卑近な例としては、ログインユーザーとして別のユーザの名前が表示されるとか

Wednesday, April 2, 2014

Announcing Unco - undo changes to files made by any command

Being sick of myself occasionally wiping off the changes made to files by running wrong commands, I have started writing a program called "Unco" (pronunciation: an-ko) - a command that records the changes to the file system, and let the users undo the changes afterwards if necessary.

Unlike existing command-level solutions like aliasing rm to trash-cli, Unco is designed to be capable of undoing changes made by any program; it hooks the library calls that affect the file system and records the changes for later undoing.

The following scenario illustrates how it can be used, in case of git.
  1. instruct the shell to record all git commands
    % alias git="unco record -- git"
    
  2. edit file under the git repository
    % vi program.c
    
  3. Oops! I have accidentally reset the changes
    % git reset --hard HEAD
    
  4. don't worry, just undo the last action
    % undo history
    index    command (*=undone)
         1   git reset --hard HEAD
    % unco undo 1
    
As described, you can apply unco for rm or make install or whatever command.

The development is still in early stages, and I would not advise anybody not capable of debugging the code by oneself to use it. But for those interested, the repo is at github.com/kazuho/unco.

For the time being, the program runs on OS X and linux (edited Apr. 3 2014)only on OS X. Hopefully the command may be polished up so that it can be turned on by default; i.e. record all commands run on the shell by default.