monolithic kernel

Rubyで安全なWebアプリを作るためのメモ

February 18, 2012

    RubyでWebアプリケーションを作るときにセキュリティ関連でやっておくべきことのメモです。

    以下の4つの問題について、Sinatra・Hamlを使っている環境(うちの環境)での対策方法を説明しています。それぞれの問題についての詳細はここでは触れないので、徳丸本を読むとよいと思います。

    • XSS
    • CSRF
    • クリックジャッキング
    • IEのsniffing

    XSS対策

    エスケープ漏れを防ぐ

    きちんとエスケープをする、というのは言葉にすると簡単ですが手作業で実現するのは極めて困難です。まともなテンプレートエンジンにはエスケープを自動で行う機能が付いているのでそれを利用しましょう。エスケープを自動化することで、デフォルトでエスケープを行い、指定があった場合のみエスケープしないようにすることができ、エスケープ漏れを最小限に抑えられます。

    app.rb

    class App < Sinatra::Base
      set :haml, :escape_html => true
    end

    index.haml

    %p
      = "ここに書いた内容は自動でエスケープされます<script>alert(0);</script>"
    %p
      != "こっちに書いた内容はエスケープされません<script>alert(0);</script>"

    XSSがあったときの影響を抑える

    そうは言ってもうっかりXSSを作り込んでしまうことがないとは言い切れません。X-XSS-Protectionヘッダを追加することで、ブラウザ側でXSSを検出したときに真っ白のページを表示してスクリプトの実行を防いでくれます。しかし、回避する方法が発見されることもあるので、あまり過信せず、エスケープ漏れをなくすよう努めた上で利用しましょう。

    nginxの設定ファイルに以下のように記述することでヘッダを付加できます。

    nginx

    add_header X-XSS-Protection "1; mode=block";

    Apache

    Header set X-XSS-Protection "1; mode=block"

    CSRF対策

    rack_csrfというgemが用意されているので利用します。

    $ gem install rack_csrf

    rack_csrfでは、sessionとformにtokenを仕込んでおいて、postされたときにsessionとformの値が一致すれば正規の操作と判断します。もしformの値が間違っていたり、値が付加されていない場合はRack::Csrf::InvalidCsrfToken例外が発生するので、適当にエラーページを表示します。

    app.rb

    require 'rack/csrf'
    
    class App < Sinatra::Base
      disable :session
      use Rack::Session::Cookie, :secret => 'ランダムな文字列'
      use Rack::Csrf, :raise => true
    
      helpers do
        def csrf_tag
          Rack::Csrf.csrf_tag(env)
        end
      end
    
      get '/' do
        haml :index
      end
    
      error Rack::Csrf::InvalidCsrfToken do
        ...
      end
    end

    index.haml

    %form{:action => '/post', :method => 'POST'}
      ...
      != csrf_tag

    クリックジャッキング対策

    X-Frame-OptionsヘッダにDENYを設定しておくと、自サイトのコンテンツを外部サイトのフレーム内に表示できなくなるため、クリックジャッキング攻撃を防ぐことができます。IE8以降とその他の主要なブラウザが対応しています。

    nginx

    add_header X-Frame-Options DENY;

    Apache

    Header set X-Frame-Options DENY

    IEのsniffing対策

    IEはContent-Typeではなくファイルの内容からファイルの種類を判定するため、HTMLタグっぽい文字列が含まれたテキストファイルや画像ファイルがHTML扱いされてしまうことがあります。もしそのファイルにJavaScriptが含まれていた場合、XSSが発生してしまいます。IE7以下の場合はどうしようもありませんが、IE8以降であればX-Content-Type-Optionsヘッダにnosniffを指定することでsuniffingを防げます。

    ただ、X-Content-Type-Optionsヘッダが指定されているとChromeの挙動が変わることがあるので注意が必要です。

    nginx

    add_header X-Content-Type-Options nosniff;

    Apache

    Header set X-Content-Type-Options nosniff