この文書は2016年以降更新されていません

Ruby on Rails に関するチートシート

OWASP 作成
ジャンプ先: 移動検索
Cheatsheets-header.jpg

最終改訂日 (yy/mm/dd): 2015/03/09

はじめに

このチートシートは、Ruby on Rails のセキュリティに関する簡単で基本的なヒントを開発者向けに提供することを目的としています。このシートでは、Rails コアによる Rails セキュリティガイドで取り上げられている問題を補完、増補、強調しています。Rails フレームワークは、多くの単調な作業から開発者を解放し、複雑なタスクを迅速かつ容易に実行できるようにするための手段を提供します。Rails の内部構造に不慣れな新しい開発者には、アプリケーションの基本的な側面を保護するための一連の基本ガイドラインが必要となることが予想されます。このドキュメントのねらいは、このような指針を提供することです。

項目

コマンドインジェクション

Ruby は、文字列に基づいて新しい Ruby コードを動的に構築する "eval" という関数を備えています。また、Ruby にはシステムコマンドを呼び出す方法が複数あります。

  eval("Ruby コードをここへ挿入")
  System("OS コマンドをここへ挿入")
  `ls -al /`   (OS コマンドをバッククォートで囲む)
  Kernel.exec("OS コマンドをここへ挿入")

これらのコマンドは非常に有用ですが、Rails ベースのアプリケーションでこれらを使用するときには細心の注意を払う必要があります。通常は、使用すべきではありません。使用する必要がある場合は、入力可能値のホワイトリストを使用して、あらゆる入力をできるだけ入念に検証します。「Ruby Security Reviewer's Guide」にインジェクションに関するセクションがあります。また、OWASP の参考資料が多数あり、「Command Injection」から辿ることができます。

SQL インジェクション

Ruby on Rails は、多くの場合、ActiveRecord と呼ばれる ORM とともに使用されますが、柔軟性があり、他のデータソースでも使用できます。通常、きわめて単純な Rails アプリケーションでは、Rails モデルに対するメソッドの使用を通じて、データのクエリが実行されます。多くのユースケースでは、SQL インジェクションに対する防御が追加設定なしで適用されます。しかし、SQL インジェクションを可能にしてしまうコードが作成される場合もあります。

次に例を示します (Rails 2.X スタイル):

   @projects = Project.find(:all, :conditions => “name like #{params[:name]}”)

Rails 3.X の例:

   name = params[:name]
   @projects = Project.where(“name like ‘“ + name + “‘“);

どちらのケースでも、name パラメーターがエスケープされていないため、ステートメントへのインジェクションが可能です。

この種のステートメントを構築する場合、次のようなイディオムを使うべきです。

   @projects = Project.find(:all, :conditions => [ “name like ?”, “#{params[:name]}”] )

AREL ベースのソリューション:

   @projects = Project.where("name like ?", "%#{params[:name]}%")

ユーザーが制御する入力に基づいて SQL ステートメントを構築しないよう注意してください。より実際的で詳細な例が、rails-sqli.org にあります。OWASP は、SQL インジェクションに関する広範な情報を保有しています。

クロスサイトスクリプティング (XSS)

Rails 3.0 では、XSS に対する防御が既定の動作となっています。ビューへの文字列データの表示時、文字列データはブラウザーに送り返される前にエスケープされます。これはとても有用ですが、よくあるケースとして、開発者が、リッチテキストの編集を可能にするためなどの目的で、この保護をバイパスすることがあります。タグをそのままの状態にして変数をフロントエンドに渡す必要がある場合、.erb ファイル (Ruby マークアップ) で次のように記述したくなります。

   <%= raw @product.name %>   
   <%= @product.name.html_safe %>       これらは "してはいけない" ことの例です。
   <%= content_tag @product.name %>

残念なことに、raw をこのように使用しているフィールドはすべて XSS の潜在的な標的になります。また、html_safe についても、一般に広まっている誤解があります。この記事には、基礎の SafeBuffer メカニズムに関する詳細な説明があります。文字列の出力の準備方法を変更するその他のタグも、同様の問題を発生させます。content_tag もその 1 つです。

ユーザーからの HTML コンテンツを受け入れる必要がある場合は、アプリケーションでリッチテキスト用のマークアップ言語 (Markdown や Textile など) を使用し、HTML タグは拒否することを検討してください。 これは、有害な可能性がある HTML コンテンツを含む入力の受け入れを防止するのに役立ちます。ユーザーによる HTML の入力を制限できない場合は、あらゆる javascript の実行を禁止するコンテンツセキュリティポリシーの導入を検討してください。さらに、使用可能なタグのホワイトリストを作成できる #sanitize メソッドの使用を検討します。ただし、このメソッドは不備があることが何度も判明しているため、完全なソリューションとはなりません。

しばしば見過ごされる XSS 攻撃ベクトルの 1 つに、リンクの href 値があります。

   <%= link_to “Personal Website”, @user.website %>

@user.website に、"javascript:" で始まるリンクが含まれている場合、生成されたリンクをユーザーがクリックすると、コンテンツが実行されます。

   <a href=”javascript:alert(‘Haxored’)”>Personal Website</a>

OWASP では、トップレベルページの 1 つである「OWASP Cross Site Scripting」で XSS に関する一般情報を提供しています。

セッション

既定では、Ruby on Rails は Cookie ベースのセッションストアを使用します。これは、特に設定を変更しない限り、セッションはサーバー上で期限切れにならないことを意味します。つまり、既定のアプリケーションは、再生攻撃に対して脆弱である可能性があることになります。また、これは、センシティブな情報はセッションに含めるべきではない、ということも意味します。

ベストプラクティスは、データベースのセッションを使用することです。幸いなことに、これは Rails では非常に容易です。

   Project::Application.config.session_store :active_record_store

OWASP セッション管理に関するチートシート」があります。

認証

通常、Rails はそれ自体では認証機能を提供しません。しかし、Rails を使用している開発者のほとんどは、Devise や AuthLogic などのライブラリを活用して認証機能を実装しています。Devise で認証を有効にするには、単にコントローラーで次のように指定します。

   class ProjectController < ApplicationController
       before_filter :authenticate_user

他の方法と同様に、これは例外をサポートしています。既定では、Devise で必要となるパスワード文字数はわずか 6 文字です。最低文字数は次のファイルで変更できます。/config/initializers/devise.rb

   config.password_length = 8..128

複雑性を強制する方法はいくつかあります。1 つはユーザーモデルに検証を導入することです。

   validate :password_complexity
   def password_complexity
      if password.present? and not password.match(/\A(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+\z/)
          errors.add :password, "must include at least one lowercase letter, one uppercase letter, and one digit (小文字、大文字、数字をそれぞれ 1 文字以上含んでいなければなりません)"
      end
   end

OWASP 認証に関するチートシート」があります。

セキュリティで保護されていない直接的なオブジェクト参照または強制的ブラウズ

既定では、Ruby on Rails アプリは RESTful URI 構造を使用します。これは、パスがしばしば直観的で推測可能であることを意味します。ユーザーが別のユーザーに属するデータへのアクセスやデータの変更を試みようとするのを阻止するには、アクションを明確に制御することが重要です。標準的な Rails アプリケーションのゲートの外には、そのような組み込みの保護機能はありません。手動により、コントローラーレベルでこの制御を行うことは可能です。

また、cancancan (cancan の後継) や pundit などの、リソースベースのアクセス制御ライブラリを使用してこの制御を行うことも可能であり、おそらくこちらの方法を検討するのが良いでしょう。この方法により、データベースオブジェクトに対するすべての操作が、アプリケーションのビジネスロジックによって認可されるようになります。

OWASP Top 10 ページには、このクラスの脆弱性に関する一般情報があります。

CSRF (クロスサイトリクエストフォージェリ)

Ruby on Rails には、CSRF に対する特別なサポートが組み込まれています。これを有効化する、または有効化を保証するには、ベース ApplicationController を見つけて、次のようなディレクティブを探します。

   class ApplicationController < ActionController::Base
       protect_from_forgery

この種の制御の構文には、例外を追加するための方法が含まれています。例外は API やその他の理由で役立つことがありますが、その必要性をよく検討して、意識して組み込む必要があります。次の例の場合、Rails ProjectController は show メソッドに対して CSRF 防御を提供しません。

  class ProjectController < ApplicationController
      protect_from_forgery :except => :show

また Rails は、既定では、HTTP GET リクエストに対して CSRF 防御を提供しないことにも注意してください。

OWASP のトップレベルページの 1 つでは、CSRF について説明しています。

Mass Assignment と Strong Parameters

Mass Assignment に関する主な問題は、ベース Rails では既定で修正されており、新規にプロジェクトを生成する場合には問題ありませんが 、以前のプロジェクトやアップグレードされたプロジェクトでは、この問題について理解し、変更可能とされている属性以外は公開されないようにすることが重要です。

モデルの操作時、プログラマーが次のように明示的に指示しない限り、ポストされたフォームからモデルの属性にアクセスすることはできません。

   class Project < ActiveRecord::Base
       attr_accessible :name, :admin
   end

上の例に基づいて admin 属性がアクセス可能である場合、次のことが可能になることがあります。

   curl -d “project[name]=triage&project[admin]=1” host:port/projects

アクセス可能な属性はどれか、そして実際にアクセス可能にする必要があるか、を確認してください。3.2.3 より前のバージョンの Rails を使用している場合は、次の方法で必ず属性のホワイトリストを作成する必要があります。

   config.active_record.whitelist_attributes = true

Rails 4.0 での属性の可視性処理の推奨アプローチは、Strong Parameters を使用することです。また、Rails 3.x アプリケーションでは strong_parameters gem を、Rails 2.3.x アプリケーションでは strong_parameters_rails2 gem をそれぞれ使用できます。

リダイレクトと転送

多くの場合、Web アプリケーションには、クライアントが提供したデータに基づいてユーザーを動的にリダイレクトする機能が必要になります。明確に言うと、動的なリダイレクトを可能にするためには、通常、アプリケーションへのリクエスト内のパラメーターに、クライアントによって URL が挿入されなければなりません。アプリケーションでリクエストが受信されると、ユーザーはリクエスト内に指定された URL にリダイレクトされます。次に例を示します。

http://www.example.com/redirect?url=http://www.example_commerce_site.com/checkout

上のリクエストでは、ユーザーは http://www.example.com/checkout にリダイレクトされます。この機能に関連するセキュリティの問題は、組織の信頼されたブランドを使ってユーザーを有害なサイトに誘導するフィッシング攻撃の存在です。次の例では、このような有害サイトとして "badhacker.com" を使用しています。例:

http://www.example.com/redirect?url=http://badhacker.com

限定的とはいえ、最も基本的な防御は、:only_path オプションを使用することです。これを true に設定すると、本質的に、あらゆるホスト情報が削除されます。ただし、:only_path オプションは第 1 引数の一部でなければなりません。第 1 引数がハッシュテーブルでない場合、このオプションを渡すことはできません。カスタムのヘルパーまたはホワイトリストがないときに有効なアプローチの 1 つは、次のとおりです。

 begin
   if path = URI.parse(params[:url]).path
     redirect_to path
   end
 rescue URI::InvalidURIError
   redirect_to '/'
 end

ユーザー入力と承認されたサイトのリストとの照合や TLD と正規表現との照合が必須である場合、URI.parse() などのライブラリを使用してホストを取得し、ホスト値を正規表現パターンと照合することは、理にかなっています。このような正規表現は、少なくともアンカーを含んでいなければなりません。でなければ、攻撃者が検証ルーチンをバイパスする可能性が高まります。

例:

   require ‘uri’
   host = URI.parse(“#{params[:url]}”).host
   validation_routine(host) if host    # これは javascript://trusted.com/%0Aalert(0) に対して脆弱である可能性があるため、.scheme と .port もチェックする
   def validation_routine(host)
       # この検証ルーチンでは \A および \z をアンカー *not* ^ および $ として使用
       # また、ホスト値をホワイトリストと照合するのも良い
   end

また、ユーザー入力パラメーターへのブラインドリダイレクトも XSS につながる可能性があります。例:

   redirect_to params[:to]
   
   http://example.com/redirect?to[status]=200&to[protocol]=javascript:alert(0)//

この種の脆弱性に対する明らかな修正は、特定のトップレベルドメイン (TLD) に制限するか、特定のサイトを定義するか、またはキーとその値とをマップすることです。例:

   ACCEPTABLE_URLS = {
       ‘our_app_1’ => “https://www.example_commerce_site.com/checkout”,
       ‘our_app_2’ => “https://www.example_user_site.com/change_settings”
   }

http://www.example.com/redirect?url=our_app_1

  def redirect
      url = ACCEPTABLE_URLS[“#{params[:url]}”]
      redirect_to url if url
  end

未検証のリダイレクトと転送に関する一般情報を示す OWASP リソースがあります。

レンダリングパスの動的指定

Rails では、"render" メソッドを呼び出すことによって、コントローラーのアクションとビューで、どのビューまたはその一部をレンダリングするかを動的に決定することができます。テンプレート名またはその一部としてユーザー入力を使用すると、攻撃者により、 管理ページなどの任意のビューをアプリケーションがレンダリングするように、操作されてしまう可能性があります。

レンダリングするビューをユーザー入力に基づいて決定する場合は、注意が必要です。ビューの名前やパスの中でユーザー入力を使用することは、できるだけ避けてください。

クロスオリジンリソース共有 (CORS)

ときには、別のドメインとリソースを共有する必要が生じることがあります。たとえば、AJAX リクエストを介して別のドメインにデータを送信するファイルアップロード機能などのリソースがあります。このような場合、Web ブラウザーが従う同一生成元の規則を曲げなければなりません。これは、HTML5 標準に準拠したモダンブラウザーでは可能ですが、その際に注意すべきことが 2、3 あります。

たとえば非定型の Content-Type ヘッダーなど、非標準の HTTP コンストラクトを使用する場合には、次のことが適用されます。

受信側のサイトでは、このようなリクエストの作成を許可されたドメインのみのホワイトリストを作成するとともに、OPTIONS リクエストと POST リクエストの両方のレスポンスに Access-Control-Allow-Origin ヘッダーを設定する必要があります。これは、リモートまたは受信側サイトがリクエスト元のドメインを許可しているかどうか判定するために、最初に OPTIONS リクエストが送信されるためです。次に、2 番目のリクエストとして POST リクエストが送信されます。ここでも、トランザクションが成功として表示されるためには、ヘッダーが設定されていなければなりません。

標準の HTTP コンストラクトを使用する場合:

リクエストの送信後、レスポンスを受信すると、ブラウザーはレスポンスヘッダーを調べて、レスポンスが処理可能かどうか、また処理すべきかどうかを確認します。

Rails でのホワイトリストの作成:

Gemfile

   gem 'rack-cors', :require => 'rack/cors'

config/application.rb

   module Sample
       class Application < Rails::Application
           config.middleware.use Rack::Cors do
               allow do
                   origins 'someserver.example.com'
                   resource %r{/users/\d+.json},
                       :headers => ['Origin', 'Accept', 'Content-Type'],
                       :methods => [:post, :get]
               end
           end
       end
   end

セキュリティ関連ヘッダー

ヘッダー値を設定するには、単に、コントローラー内 (多くの場合、before/after_filter 内) のハッシュとして、response.headers オブジェクトにアクセスします。

 response.headers['X-header-name'] = 'value'

Rails 4 は、指定された値を自動的に適用する "default_headers" 機能を備えています。これは、ほぼすべてのクラスのほとんどのヘッダーに有効です。

 ActionDispatch::Response.default_headers = {	  	
   'X-Frame-Options' => 'DENY', 	
   'X-Content-Type-Options' => 'nosniff',	  	
   'X-XSS-Protection' => '1;'
 }

Strict Transport Security は特殊なケースであり、環境ファイル (production.rb など) で設定します。

 config.force_ssl = true

他の方法を使用したい場合は、コンテンツセキュリティポリシーの抽象化を提供する、同じ動作のライブラリ (secure_headers) もあります。このライブラリは、ユーザーエージェントに基づいてロジックを自動的に適用することによって、簡潔なヘッダーセットを生成します。

ビジネスロジックのバグ

どのようなテクノロジのどのようなアプリケーションであっても、セキュリティのバグを発生させるビジネスロジックを内部に含む可能性があります。ビジネスロジックのバグは、自動ツールでは検出が不可能または困難です。ビジネスロジックのセキュリティバグを防止する最善の方法は、コードをレビューし、ペアプログラミングを実施し、単体テストを作成することです。

攻撃対象領域

一般に、Rails では、どの URL がアクセス可能であり、またアクセス可能な URL をどのコントローラーによって処理すべきかが /config/routes.rb ファイルによって指示されるため、オープンリダイレクトやパストラバーサルといったタイプの脆弱性は回避されます。攻撃対象領域のスコープについて検討する際には、この routes ファイルのチェックが非常に役立ちます。次に例を示します。

   match ':controller(/:action(/:id(.:format)))' # これは、"してはいけない" ことの例です。

この場合、このルートでは、あらゆるコントローラーのあらゆるパブリックメソッドがアクションとして呼び出される可能性があります。開発者は、あらかじめ意図されたコントローラーメソッド以外のメソッドに、意図された方法以外の方法で、ユーザーがアクセスできないようにする必要があります。

機密のファイル

Ruby on Rails アプリの多くは、オープンソースであり、公開されたソースコードリポジトリ上にホストされます。これに該当する場合も、またコードが企業のソース管理システムに格納される場合も、一部のファイルについては、除外するか、または慎重に管理する必要があります。

   /config/database.yml                 -  実稼働の証明書を含むことがあります。
   /config/initializers/secret_token.rb -  セッション Cookie のハッシュに使用されるシークレットを含みます。
   /db/seeds.rb                         -  ブートストラップ管理ユーザーなどのシードデータを含むことがあります。
   /db/development.sqlite3              -  実際のデータを含むことがあります。 


暗号化

Rails では OS の暗号化が使用されます。一般に、独自の暗号化を作成することは常にやめるべきです。

Devise では、既定で、パスワードのハッシュに bcrypt が使用されます。これは適切なソリューションです。以下の config では通常、stretch 回数は 10 に設定されます。/config/initializers/devise.rb

   config.stretches = Rails.env.test? ? 1 : 10

Rails の更新、および依存関係更新プロセスの設定

2013 年の初頭に、Rails フレームワークの重大な脆弱性がいくつか特定されました。現在のバージョンに遅れをとっていた組織は、更新がより面倒なものになり、更新の過程で、フレームワーク自体のソースコードへのパッチ適用などについて、より難しい決定を強いられました。

Ruby アプリケーション全般に関連する別の問題として、ほとんどのライブラリ (gem) が作成者によって署名されていないという問題があります。信頼されたソースからのライブラリを使用して Rails ベースのプロジェクトを構築することは文字通り不可能です。推奨手法の 1 つは、使用する gem を監査することです。

一般に、依存関係の更新プロセスを設定することが重要です。たとえば、更新プロセスをトリガする次のような 3 つのメカニズムを定義します。

  • 毎月または四半期ごとに、依存関係全般を更新する。
  • 毎週、重要なセキュリティの脆弱性について考慮し、場合によっては更新をトリガする。
  • 例外的な状況では、緊急更新の適用が必要なこともある。

ツール

Rails アプリケーション用のオープンソースなコード解析ツールである brakeman を使用することで、潜在的なさまざまな問題を特定できます。このツールでは、包括的なセキュリティ調査結果は必ずしも得られるとは限りませんが、検出が容易な問題は見つかります。Rails 内の潜在的な問題を見つける良い方法は、brakeman ドキュメントで警告タイプを調べることです。

依存関係セット内のセキュリティ問題の追跡に使用できる、https://gemcanary.com/https://gemnasium.com/ などの新しいツールがあります。

別のツール領域として、セキュリティテストツール Gauntlt があります。このツールは cucumber 上に構築され、gherkin 構文を使って攻撃ファイルを定義します。

2013 年 5 月にリリースされた codesake-dawn は、brakeman スキャナーに非常によく似た静的アナライザーであり、Rails、Sinatra、および Padrino Web アプリケーションのセキュリティの問題を分析します。バージョン 0.60 には Ruby 固有の CVE セキュリティチェックが 30 個以上も含まれており、さらに今後のリリースでは、クロスサイトスクリプティングと SQL インジェクションに対するカスタムチェックが追加される見込みです。

Authors and Primary Editors

Matt Konda - mkonda [at] jemurai.com
Neil Matatall neil [at] matatall.com
Ken Johnson cktricky [at] gmail.com
Justin Collins justin [at] presidentbeef.com
Jon Rose - jrose400 [at] gmail.com
Lance Vaughn - lance [at] cabforward.com
Jon Claudius - jonathan.claudius [at] gmail.com
Jim Manico jim [at] owasp.org
Aaron Bedra aaron [at] aaronbedra.com
Egor Homakov homakov [at] gmail.com

関連資料と参考資料

Other Cheatsheets

Developer Cheat Sheets (Builder)

Assessment Cheat Sheets (Breaker)

Mobile Cheat Sheets

OpSec Cheat Sheets (Defender)

Draft Cheat Sheets