Software-Defined どさにっき 〜2015年5月上旬〜

by やまや
<< = >>

2015年5月2日(土)

ファイルアップローダーのセキュリティ

_ 徳丸さんとこ。 Apacheの多重拡張子にご用心

ファイルのアップロードは、実は簡単ではないととらえるべきだと思います。
アップロード自体は難しくもなんともないよね。アップロードしたファイルをダウンロードさせるのであれば気をつけなきゃいけないことはたくさんあるけど。

_ ファイルをダウンロードさせるためのスクリプトなのであれば、アップロードだけじゃなくてダウンロードの部分まで面倒を見るべき、つまり推奨されてるとおり、対策の (3)(4) が正道だと思う。

_ が、たとえば、プログラムを1ビットも書かなくても、WebDAV という仕組みを使えばファイルのアップロードやら削除やらは好き放題できる。でも、DAV でもファイルのダウンロードは素の HTTP の GET を使うので、DAV が有効な場所でスクリプトが実行可能になってると、アップロードしたスクリプトを GET すればサーバ上で実行できてしまう。(2) のスクリプトを実行させないようにする、という対応が必要になる。

_ なんだけど、例示されてる

RemoveHandler .php
はダメ。これがダメというか、これだけじゃぜんぜん足りない。アップロードされて実行されるスクリプトは PHP だけじゃないので。SSI から <!--#exec cmd="..."--> されるかもしれないし、Windows だと chmod +x しなくても CGI が動くし、このへん全部ふさいでおかなければいけない。ということで、拡張子ごとに RemoveHandler するなんてまどろっこしいことはせず、
SetHandler default-handler
ですべてのハンドラをリセットする。最近の apache にはフィルタなんてのもあるのでこれでもまた不足で、RemoveOutputFilter でヤバげなもの(INCLUDES とか ExtFilterDefine で定義したフィルタとか)を除外する。実行可能なスクリプトじゃなくても XSS の危険があるので HTML も止めなきゃいけなくて、.html や .shtml ほか、text/html な拡張子を RemoveType しておく(ファイルの中身を見て HTML っぽかったら text/html じゃなくても HTML として解釈してしまう昔の MSIE の存在はそろそろ無視していいよね)。あと、間違っても .htaccess をアップロードできないように、できたとしても無視するように AllowOverride None しておく。このぐらいやっておくと、まあなんとか大丈夫かな?

_ つーか、2ch とか見て育った人だとうpろだとかわりと身近だろうから、こういうのは題材としていいのかもしれないけど、実装がどうの以前に、不特定多数のユーザに任意のファイルを置ける場所を提供するという行為がまず危険である、という認識が必要だと思うんだけどな。ディスクが溢れるまでファイルをアップロードし続ける、という攻撃だってできそうだし。


2015年5月4日(月) みどりの日

無題

_ GW だけど、やっぱり軽い頭痛と微熱が続いて、どこに出かけることもなくひきこもり。そんなにひどいわけでもないので日帰りで遊びにいくくらいならどうってことないんだろうけど、もし悪化したらと考えるとちょっとなぁ。

Credns

_ 先日からのうちのサーバ更新。その DNS まわり。

_ 外に見せてるゾーンは maya.st と実験用の chigumaya.jp のふたつ。後者は DNSSEC つき。せっかく構成変更したので、hidden master と public slave の二段構成に分離。…ではなく、三段構成にしてみる。

nsd (master) - credns (verifier) - nsd (slave)
こんな感じ。ゾーンは hidden master の nsd で管理。こいつで DNSSEC 署名したゾーンを更新して crednsに notify を飛ばす。credns は更新されたゾーンを取得して、正しく署名できているか検証した上で、問題がなければ slave の nsd に notify を送って AXFR。署名の検証に失敗すれば credns のところで止まるので、外部に公開している slave が壊れたゾーンを外に見せて署名検証不能、というトラブルが減る。

_ が、トラブルが減るだけで、なくなりはしない。自動で署名してくれるわけではないので期限切れには対応できないし、そのゾーン自体の整合性をチェックするだけなので、署名は正しいけどロールオーバーの手順を間違えて以前のキャッシュとの整合性が取れなくて検証失敗するような場合には対処できない。うーん、DNSSEC の運用ミスの最大の要因がこのへんなんだが、それに対応できないならほとんど使う意味ないような。

_ ちなみに、credns 自体に署名検証の機能があるわけではなく、検証ツールを外部コマンドとして呼び出すだけ。うちで使ってる署名スクリプトでは、署名の後処理として実行するコマンドを別途指定することができて、それを使って検証ツールを呼び出して失敗したらゾーンのリロードさせないということが可能なので、credns を使わなくてもやりたいことは十分できる。そういう意味でもやっぱりうちではいらん。BIND の automatic signing 機能を使ってるような場合は外部ツールを介入させるのが難しいのであると便利かも。

_ そんなわけであんまり意味はないんだけど、せっかくなんで試してみるよ。インストールしててきとーに設定して実行。…コケた。zonec がないってよ。freebsd のパッケージの作りがショボいなー、と思ったら、 credns 自体の問題だった。ちゃんとコンパイルはされていて、インストールされないだけなんで、Makefile の修正だけでいける。確認してないけどたぶん NSD3 の zonec と変わってないので、そちらがすでにあるならそっちを使えばいいと思う(すでに zonec を必要としない NSD4 の時代なのだが)。

--- Makefile.in.orig    2012-06-19 17:50:34.000000000 +0900
+++ Makefile.in 2015-05-02 17:05:34.653242868 +0900
@@ -370,12 +370,14 @@
        $(INSTALL) credns-checkconf $(DESTDIR)$(sbindir)/credns-checkconf
        $(INSTALL) credns-patch $(DESTDIR)$(sbindir)/credns-patch
        $(INSTALL) credns-xfer $(DESTDIR)$(sbindir)/credns-xfer
+       $(INSTALL) zonec $(DESTDIR)$(sbindir)/zonec
        $(INSTALL_DATA) $(srcdir)/credns.8 $(DESTDIR)$(mandir)/man8
        $(INSTALL_DATA) $(srcdir)/crednsc.8 $(DESTDIR)$(mandir)/man8
        $(INSTALL_DATA) $(srcdir)/credns-notify.8 $(DESTDIR)$(mandir)/man8/credns-notify.8
        $(INSTALL_DATA) $(srcdir)/credns-checkconf.8 $(DESTDIR)$(mandir)/man8/credns-checkconf.8
        $(INSTALL_DATA) $(srcdir)/credns-patch.8 $(DESTDIR)$(mandir)/man8/credns-patch.8
        $(INSTALL_DATA) $(srcdir)/credns-xfer.8 $(DESTDIR)$(mandir)/man8/credns-xfer.8
+       $(INSTALL_DATA) $(srcdir)/zonec.8 $(DESTDIR)$(mandir)/man8/zonec.8
        $(INSTALL_DATA) $(srcdir)/credns.conf.5 $(DESTDIR)$(mandir)/man5/credns.conf.5
        $(INSTALL_DATA) credns.conf.sample $(DESTDIR)$(nsdconfigfile).sample

_ Credns は NSD3 から fork したものなので、大部分の設定は NSD3 と同じ。違うのは verifier の部分ぐらい。

zone:
        name: "chigumaya.jp"
        zonefile: "chigumaya.jp.signed"
        allow-notify: 127.0.0.1 NOKEY
        request-xfr: 127.0.0.1 NOKEY
        notify: 192.168.1.25 NOKEY
        provide-xfr: 192.168.0.0/23 NOKEY
        verifier: /usr/local/bin/ldns-verify-zone -S -k /usr/local/etc/credns/root.key -V 2
検証を ldns-verify-zone でやるように設定しているが、署名も ldns-signzone を使っていて、どちらも ldns。あまりよくない。ldns 自体にバグがあった場合は署名側のミスを拾えない可能性があるので。今回はそもそも credns の利用自体に意味がないことを承知でやってるのでわりといいかげんだけど、ちゃんとやるのであれば署名と検証は別のベンダーが開発したツールを使いわけるべき。署名は BIND の dnssec-signzone を使う、検証を validnsyazvsでおこなうなど。validns は DNSSEC 署名されていないゾーンの、文法ミスではないけど運用上よろしくない間違い(CNAME の指してる先がないとか)もけっこう見つけてくれるので、DNSSEC 署名しない場合でも credns 経由でチェックするというのもありかも。

_ 正しいゾーンを食わせた場合。

May  3 10:53:05 <daemon.info> ayanami credns[67108]: Zone chigumaya.jp has changed.
May  3 10:53:05 <daemon.info> ayanami credns[67108]: Zone chigumaya.jp verified successfully.
May  3 10:53:05 <daemon.notice> ayanami credns[67108]: Zone verifying done... Good: 1, Bad: 0.
hidden master でわざと署名がぶっこわれたゾーンに更新してみる。credns が拒否して古いゾーンに戻されるので、slave は更新されない。
May  3 10:57:34 <daemon.info> ayanami credns[67143]: Zone chigumaya.jp has changed.
May  3 10:57:35 <daemon.err> ayanami credns[67143]: Error: Bogus DNSSEC signature for chigumaya.jp.     A
May  3 10:57:35 <daemon.err> ayanami credns[67143]: There were errors in the zone
May  3 10:57:35 <daemon.err> ayanami credns[67143]: Zone verifier for zone chigumaya.jp exited with status: 35
May  3 10:57:35 <daemon.notice> ayanami credns[67143]: Zone verifying done... Good: 0, Bad: 1.
May  3 10:57:35 <daemon.info> ayanami credns[67055]: Zone chigumaya.jp serial 1430617985 is discarded. Reverting to serial 1430617984.

_ 元が NSD なので master としての機能も残ってる。ので、credns を slave ではなく master として設定してみて壊れたゾーンを投入してみたけど、この場合は検証されずに素通りしてしまった。やっぱり slave として使わなきゃ意味ないみたい。

_ NSD3 ではなく、NSD4 をベースに作ってほしいなー、とかいろいろ改善してほしい点もあるんだけど、3年前に最初のバージョン(0.20.1 といういかにも開発途上のもの)が出たっきり、その後まったく音沙汰がない。うん、そういう意味でも、署名したらいきなりリロードせず、その前に検証コマンドを叩く、という流れは credns を使わずにスクリプトでやるのが正しいと思う。

_ ということで、credns は試してみたけど使わないことにした。ふつーに hidden master - public slave の二段構成。

_ DNSSEC まわりのスクリプトは今回を機にいろいろ書き換えたので、もう少し整理してから後日公開する予定。といっても、核となる部分はまったく手を入れてないんだけど。


2015年5月8日(金)

from(1) on imap

_ うちのメールサーバを作り直してから何週間か経ったけど、新着メールの確認がめんどくさくなった。これまでは生活環境なホストの Maildir に配送してたので、確認だけならいちいち MUA を起動しなくても、Maildir/new/ の下を直接覗けば用が足りた。が、生活環境と imap サーバを分離した上、パフォーマンスを上げるために Maildir を捨てて dovecot 独自形式に移行したのでそれもめんどくさくなった。

_ ちうことで、 imap サーバに新着メールを問い合わせるスクリプトを書いてみた。 from(1)という mbox 形式のみに対応した新着メールの送信者と到着時刻を表示するお便利コマンドの imap 対応版な感じ。ちなみに、これまで使ってた Maildir 対応版はこちら

_ スクリプト自体は、ruby の Net::IMAP のサンプル程度のことしかしてない。エラーチェックもしてない。めんどくさいからユーザ/パスワードもスクリプト内に直接埋め込み。改良の余地はいくらでもあるけど、自分にはもうこれ以上の機能は必要ないので気にしない。

_ いくつか注意点。

_ 新着確認するメールボックスは、とくに指定しなければ subscribe してるものを自動で取得するけど、数が多いとかなり時間がかかるので必要なものだけ列挙しておいた方がよいかと。

_ 表示される送信元アドレスと日時は、いずれもヘッダの from/date ではなく、envelope from (Return-Path) と、サーバに到着した内部時刻。オリジナルの mbox 版 from がそういう挙動だったし、意図してそれにあわせてある。ML なんかだと誰が送ってきたかを示すヘッダ from よりも、owner-hogehoge-ml@example.com とかで hogehoge-ml のメールだとわかった方が便利だし、いつ送ったかを示す(そしてしばしば間違ってる)ヘッダ Date よりも、いつ届いたのかという内部時刻がわかった方が新着確認という意味では便利なので。ヘッダの from/date を確認したいならメーラーで。

_ imap の基本的なコマンドしか使ってないけど、gmail ではたぶん動かない。このスクリプトが使ってる新着フラグ、Return-Path ヘッダの取得はいずれも gmail でサポートされてないらしいので。


<< = >>
やまや