2013/06/30 Category : 覚書 development DNSリバインディングとその対策(nginxとapache) DNSリバインディングというのは、IPスプーフィングがIPアドレスを詐称するのに対し、ドメイン名を詐称して攻撃対象のサーバに不正にアクセスすること。 なんとなく分かったような分からないような説明だが、つまりこういうことだ。例えば、ある攻撃者がターゲットとするサイトに第三者を介して攻撃を仕掛ける場合1.攻撃者はまず自分で罠サイト(http://xxx.com/attack(IP:123.1.2.3))を作成し、不特定の第三者にメールや掲示板を通じてアクセスさせる。(「期間限定セール情報!」等と称してURLを記載したメールをばらまくとか)2.何も知らない第三者が罠サイトにアクセスしたら、その直後にDNSサーバの設定を変更して自分のサイトのドメイン名xxx.comに対応するIPアドレスを攻撃ターゲットのサイトのもの(例:203.3.4.5)に書き換える。3.第三者がアクセスしたhttp://xxx.com/attackに、5秒毎とかにxxx.comにアクセスし直すJavaScriptが仕込んでおくと、定期的にxxx.comへのアクセスが試みられる。4.このときxxx.comに対応するIPはターゲットサイトのものに既に変更されているので、ブラウザはターゲットサイトにリクエストを送る。ざっくりとした仕組みはこんな感じ。この仕組みを、CSRFやDoS攻撃などに利用される可能性がある、ということだ。で、ターゲットになったサイトはどうやってこれを防ぐべきか、という話だが、まず5.ターゲットサイトのサーバが受け取る情報にはリクエストホスト名(Hostヘッダ)が含まれる。この攻撃をされた場合、サーバが受け取るリクエストホスト名は自サイトの物ではなく、必ずxxx.comになっている。6.だから、ターゲットサイトのサーバは「リクエストホスト名が自サイトのものでない場合はリクエストを処理しない」ようにすれば、この攻撃を回避することが出来る。7.そのためには、プログラム側で対策することも出来るし、サーバ側で対策することも出来る。8.サーバ側で対策するなら、名前ベースの仮想ホストを使うと簡単。apacheなら以下のようにダミーの仮想ホストを作成すれば良い。#ダミーのバーチャルホスト(dummy.example.jp)<VirtualHost *:80> ServerName dummy.example.jp DocumentRoot /var/www/dummy ErrorDocument 404 /index.html</VirtualHost>#正規のバーチャルホスト<VirtualHost *:80> ServerName www.example.jp#以下略ダミーの仮想ホストは全ての仮想ホストの一番上に記述する。そうすることによってこれがデフォルトのサーバとなり、ServerNameが他の仮想ホストとマッチしない場合はこれが使われる。また、nginxで対策するは以下が参考になる。http://nginx.org/ja/docs/http/request_processing.htmlここに書いてある通り、仮想サーバの挙動はapacheと同じようだ。つまり、1つ以上の仮想サーバがあり、Hostヘッダがそのどれともマッチしない場合、nginxはデフォルトのサーバを使おうとする。 デフォルトサーバは、通常は一番上に書かれているサーバ。なので、対象サーバの仮想サーバ設定より上に適当に設定を書いておけば、サイト名がマッチしない場合はそのサーバを使うようになる。このサーバに403とかをおいておくなりなんなりすれば良い。これが対策方法その1。 デフォルトサーバは、default_serverという名前で以下のように明示的に指定が出来る。これならどこに定義しても大丈夫。あとはその1の対策と一緒。これが対策その2。server { listen 80 default_server; server_name example.net www.example.net; ...} 最後の方法としては、nginxはHost名が未定義の場合、以下のように書くことで全てのリクエストをdropし、接続を閉じることが出来る。この設定は、そのままDNSリバインディングに対しても有効だと思われる。server { listen 80 default_server; server_name _; return 444;}444はnginxの特別なステータスコード。ということで、nginxを使う場合はこの設定もアリだな。それにしても、こんな面倒なことをしてまで悪いことをしたい奴らというのは、いったいどういう人種なんだろう。いつも不思議に思う。 PR
2013/06/30 Category : 覚書 development Webアプリのセキュリティ対策に関する簡単なまとめ 今のところ、私の知る限り以下のような脅威が存在する。各脅威の詳細についてはそのうち書くかもしれない。ここでは、結局どうすればいいのかをメモ程度にざっくりまとめる。攻撃1.xss(クロスサイトスクリプティング)2.CSRF(クロスサイトリクエストフォージェリ)3.ディレクトリトラバーサル4.クリックジャッキング5.セッションハイジャッキング6.IPスプーフィング7.SQLインジェクション8.バッファオーバーフロー9.OSコマンドインジェクション10.HTTPヘッダーインジェクション11.DNSリバインディング12.hashdos攻撃13.メールヘッダインジェクション対策まず、大前提として、「外部から入ってきたリクエストやファイルは全て汚染されている」と考え、以下を実施する。・リクエスト値の正常性(型、サイズ)をチェックする・レスポンスとして出力するもの全て(ヘッダ、ボディ)にエスケープ処理を施す ・ヘッダ → URL(スキームやクエリストリング含む)、クッキーの値 ・ボディ → html特殊文字の無効化 ・JS → JSONP対策・外部サイトのファイル(javascriptやcssなど)は原則として読み込まないその上で、個別対策として、以下を施す。1.xss(クロスサイトスクリプティング)・<script>要素の内容を動的に生成しない・JavaScriptからcookieを取り出せないようにする 例)プログラムでクッキーをセットする際、HttpOnly属性をつける ※アドレスバーに javascript:document.cookie と打って確認する・レスポンスヘッダのContent-Typeに文字コードの指定を含める 例)プログラム側で header['Content-Type'] = 'text/html; charset=UTF-8'・念のため、レスポンスヘッダにXSS対策をしておく 例)nginxに設定する場合 add_header X-XSS-Protection "1; mode=block";2.CSRF(クロスサイトリクエストフォージェリ)・ユーザ固有のトークン(必ずしもワンタイムである必要はない)をセッションに格納しておく。・ユーザ入力はPOSTで受けるようにし、その中にhiddenパラメータでトークンを仕込み、セッションに格納したトークンと同じかどうか確認。(同一性確認)・処理を実行する直前のページでパスワードの入力を求める(ユーザの意思の再確認)・Refererが正しいリンク元かを確認する(同一性確認)・重要な処理をした後は、ユーザ宛にメールを送信する(ユーザの意思の再確認。対策とまでは言えないが、被害を最小限にとどめる)3.ディレクトリトラバーサル・外部からのパラメータでファイルを直接開くような実装をしない。 例)File.open(params['filename'])4.クリックジャッキング・レスポンスヘッダにframe表示を許可しないことを明示する。サーバ側でやってもいいし、プログラムでやってもいい。 例)nginxに設定する場合 add_header X-Frame-Options DENY;5.セッションハイジャッキング・セッションIDを複雑で推測しづらいものにする(総当たり対策)・セッションIDをGET変数で渡さない(盗聴対策)・HTTPSの場合はcookieにsecure属性をつける(盗聴対策)・ログイン成功時に、新しくセッションを開始する(session fixation対策)・Webサーバの設定でTRACEメソッドを許可しない(cookie盗難対策) ※nginxは元々TRACEメソッドを許可しない。apacheは設定が必要。6.IPスプーフィング・サーバOSがunix系なら/etc/sysctl.confのrp_filterを有効にして送信元IPアドレスの偽装を防止する(不正侵入対策)。 例) net.ipv4.conf.all.rp_filter = 1 ※記入後、再起動することによって有効になる。・アプリケーションで不用意にIPアドレスによる認可をするような仕組みを作らない。・サーバ監視ツール等で怪しい動きをしているIPをブロックする。・IPSpoofing + DoS攻撃に対する根本的な対策は今のところないので、上記のようなサーバ監視で対処する。・Rackには対策ミドルウェアがあるので、Rackを使う場合はそれを使う(が、万能ではない)。7.SQLインジェクション・ユーザ入力値をSQL文生成に利用する際はプレースホルダを使う。8.バッファオーバーフロー 入力値チェックの際、サイズのチェックもする。9.OSコマンドインジェクション 外部からのパラメータで、実行する関数を直接指定出来てしまうような実装をしない。 例) exec(params[command])10.HTTPヘッダーインジェクション ヘッダの出力にはアプリケーションや言語に用意されているAPIを利用する。 ヘッダ生成の際、外部からのパラメータをそのまま使わない。 改行コードをサニタイズする(cookie含む。APIがサニタイズ出来ない場合は自前で実装する)。11.DNSリバインディング ダミーのバーチャルホストを用意する。nginxなら以下のようにダミー専用サーバをおけばオッケー。server {listen 80 default_server;server_name _;return 444;}12.hashdos攻撃 Rubyなら 1.9.0以降を使う。13.メールヘッダインジェクション 外部入力はメールボディにのみ出力し、ヘッダは固定値にする 出来るだけ開発環境や言語に用意されているメール送信用APIを使用する HTMLで宛先を指定しないこれらをしっかり行うことにより、大抵の攻撃から身を守ることが出来る。