第1章 総論
Webアプリケーションフレームワーク

ここでは、Webアプリケーションフレームワークが備えるセキュリティ機能に注目して、その利活用を考えていただく題材のひとつとして Ruby On Rails 3 をとりあげる。

開発環境となるフレームワーク

(1) プログラマが開発する部分は減る

Webアプリケーションフレームワークとは、Webアプリケーションの骨組みを提供し、開発を助けてくれる仕組みのことをいう。Webアプリケーションに共通に必要な機能をいくつも備えているため、プログラマは、自分の問題を解決するコードの記述に集中できるようになる。

framework

(2) プログラミング言語に依存するフレームワーク

これまでに多くのWebアプリケーションフレームワークが作られ、さらに増えつつある。個々のフレームワークが提供する機能の多さや使い方には、さまざまなものがある。
各フレームワークのソフトウェアのスタイルに注目してみると、XMLで各種設定を詳しく記述するもの、「設定より規約(Convention over Configuration)」 のパラダイムから可能な限り設定ファイルへの記述を要しないようにするもの、出来合いのコンテンツ管理システム(CMS)の体裁をもちながら拡張のためのAPIを豊富に提供するもの、異なるフレームワークどうしを結びつけることを得意とするもの等、多様である。

    表 代表的なWebアプリケーションフレームワーク
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
     プログラミング言語 フレームワーク名
     ──────────────────────────────
     Java        Apache Struts、Spring、Tapestry、Apache Shiro 等
     Ruby        Ruby on Rails、Merb、Sinatra 等
     PHP         CakePHP、CodeIgniter、Drupal、Joomla、MODx 等
     Python       Django、Nevow、TurboGears 等
     Perl         Catalyst、Interchange、Mason 等
     ──────────────────────────────

Ruby on Rails とセキュアプログラミング

(1) Ruby on Rails

著名なWebアプリケーションフレームワークのひとつに、Ruby on Rails がある。Ruby on Rails は、プログラミング言語 Ruby を対象として作られたWebアプリケーションフレームワークである。2004年7月に初めて登場し、2010年8月29日にはバージョン3が正式リリースされた。

Ruby on Rails は、多くの機能を備えた部類のフレームワークである。主に次の機能を備えている。

  • Web アプリケーションの基本構造
  • セッション維持の仕組み
  • HTTPリクエストと処理モジュールのマッピング
  • テンプレートエンジンによる Webページの生成
  • 入力検査の仕組み
  • ユーザ認証とアクセス認可の仕組み
  • データベースアクセス(O/R マッピング[注]等)
  • REST サポート(URLのマッピング)
  • Ajax サポート
  • キャッシュ 等

Ruby on Rails は、Ruby言語がもつ拡張性の高さを利用して作られている。Rubyでは、実行時にクラスの機能を拡張することができる。そのことを利用して、新しい「命令」をいくつも定義し、ひとつのクラスをドメイン固有言語(DSL)の処理系として使うことができる。

プログラミングの場面では、そのようにして定義された Ruby on Rails 特有の「命令」を多数用いることになる。

(2) Ruby on Rails 上のセキュアプログラミング

Ruby on Railsはバージョン2から、SQL注入等の著名な脆弱性への対応が考慮され始めたと言われている。それは、現在の最新版(バージョン3)においても引き継がれ、拡充されている。

Ruby on Rails のセキュアプログラミング機能、およびセキュリティの考慮事項には、主に次のものがある。
  
   ・著名な脆弱性対策
     a) SQL注入対策
     b) スクリプト注入(XSS)対策
     c) リクエスト強要(CSRF)対策

  ・入力値対策
     d) 入力値検査
     e) Taintを利用した入力値追跡

  ・計画的なセキュリティ機能性
     f) ユーザ認証
     g) アクセス認可

これらのうち、a) 〜 d) が、Ruby on Rails そのものが備えているものであり、e) 〜 g) は、サードパーティによるプラグイン等が提供している機能である。

a) SQL注入対策

Ruby on Rails では(バージョン2以降)変数バインディング機能を用いることで、不用意な文字列連結によるSQL注入脆弱性の発生を回避できるようになっている。

   例
     (1) r1 = Persons.all(:conditions => ["name = ?", params[:x]])
     (2) r2 = Persons.where("name = ?", params[:x])

上記のうち、(1) がバージョン2、(2) がバージョン3のスタイルである。

これらの変数バインディングの実装であるが、Ruby on Rails の中のデータベース・アダプタ・クラスにおいて、それぞれのデータベース・ソフトウェアに応じた特殊文字のエスケープ処理を設けることによって実現されている。データベース・ソフトウェアの prepared statement 機能は利用されていない。

ところで、文字列連結によるSQL文の組み立てはAPI の上では禁止されていないので注意が必要である。例えば、次のような書き方は避けるべきである。

   避けるべき例
     (1) r1 = Persons.all(:conditions => ["name = '#{params[:x]}'"])
     (2) r2 = Persons.where("name = '#{params[:x]}'")

◆Rails 3 で増やされたO/Rマッパーのメソッド

以前から Ruby on Rails には、ActiveRecord と呼ばれるO/Rマッパーがバンドルされてきたが、Ruby on Rails 3 では、この ActiveRecord にも改造が施された。データベース・クエリに ARel と呼ばれるドメイン固有言語(DSL)が導入されたので ある。

ARel のプログラミングは、従来のようにSQL文全体を一度に記述するのではなく、select, from, where, group といった、SQLの構成要素に対応したメソッドを呼び出して、Relation クラスのインスタンスの上にクエリの条件を追加してゆくスタイルをとる。

ARel の導入で、例えば、次のようなメソッドが追加されている。

   (1) Rails 2 までに存在していたメソッド
        find, first, last, all, exists?, count_by_sql, find_by_sql,
        create, update, update_all, delete_all, destroy_all 等

   (2) Rails 3 から追加されたメソッド
        select, from, where, group, having, includes, joins,
        limit, order, reorder,
        create_with, eager_load, preload
        average, calculate, count, maximum, minimum, sum 等

ARel の導入にともなって増やされたメソッドにおいても、変数バインディングの機能が設けられているので、常にそれを用いることを推奨する。

クエリを断片ごとに記述する ARel のメソッド呼び出しは、見た目は異なっていても、相変わらずSQL文を操作しているのだという意識をもち、SQL注入脆弱性に用心する必要がある。

b) スクリプト注入対策

Ruby on Rails 2 では、出力ページのERBテンプレート(rhtmlファイル)に例えば次のような記述をすることによって、& " < > の記号にエスケープ処理を施した上で値を出力させることができる。

   Rails 2 の例
     <%= h @name %>

この h メソッドは、ERB::Util クラスの html_escape メソッドの別名である。

Ruby on Rails 3 では、ERBテンプレートにおける h メソッドの適用がデフォルトになった。
  
    Rails 3 の例
     <%= @name %>

何も書かなければ、h メソッドによるエスケープ処理が適用される。これに伴い、逆に、このエスケープ処理を敢えて行わせないための raw メソッドが導入された。

   Rails 3 の例(推奨はしない)
     <%= raw @name %>

c) リクエスト強要(CSRF)対策

Ruby on Rails ではリクエスト強要(CSRF)対策の、フォームへのトークンの埋め込みとフォームデータを受信した際のトークンの照合が自動で行われる。
  
1) トークンの自動埋め込み
   
form_for 等のメソッドで生成するフォームには、自動でリクエスト強要(CSRF)対策のトークンが自動で埋め込まれる。Rails 2 ではトークンの固定値をプログラマが指定する形態が存在したが、Rails 3 では、処理系がランダムな値を生成するよう変わっている。

2) トークンの自動照合

コントローラ・クラスのビジネスロジックが呼び出される前に、リクエスト強要(CSRF)対策のトークンの照合が自動で行われる。ただし、照合が行われるのは次のようなHTTPリクエストの場合である。

  • POSTで送信されるフォームデータに限られる。
  • protect_from_forgery 命令によって指定されたコントローラ・クラスとメソ ッドの範囲。デフォルトの保護対象は、すべてのコントローラクラスの全メソッド(ただしPOSTで呼ばれるもの)である。

このリクエスト強要(CSRF)対策のトークン自動照合は、Ruby on Rails が備えているbefore_filter という機能を用いて実現されている。この before_filter を用いると、ビジネスロジックと、そのビジネスロジックの呼出をWebクライアントに許すか否かのセキュリティロジックとを分離して配置することが可能である。

所定のセキュリティロジックを配置しておけば、プログラマはビジネスロジックの記述に集中することができ、また、ソースコードをシンプルに保つことができる。

d) 入力検査

Ruby on Rails アプリケーションの「モデル」クラス群には、項目ごとの入力値チェックを指定できるvalidates 指令および validates_xxx 指令群が用意されている。

Ruby on Rails 2 では、例えば、次のような validates_xxx 指令群を用いて入力値検査を指定することができる。

  • validates_presence_of :name
    (項目 name の値が空でないこと)
  • validates_length_of :password, :minimum => 8, :maximum => 20
    (項目 password の値が8桁以上20桁以下であること)
  • validates_format_of :email, :with => /\A[-_.\w]+@[-\w]+\.[-.\w]+\z/
    (項目 email の値が当該正規表現にマッチすること)
  • validates_inclusion_of :gender, :in => %w( m f )
    (項目 gender の値が m または f のみであること)
  • validates_uniqueness_of :customer_code, :case_sensitive => false
    (項目 customer_code がDBテーブル中で重複しないこと。大文字小文字は
    区別せず比較する) 等

Ruby on Rails 3 からは、validates 指令が加わった。ひとつの入力項目の複数の検査仕様を、ひとつの validates 指令を使って記述できるようになった。

  • validates

この validates 指令および validates_xxx 指令群は、アプリケーションの「モデル」部分、すなわちActiveRecord 継承クラスに記述する。検査は値がデータベースへの格納の前に行われる。

データベースに格納されるデータの仕様への合致は確保できるが、「モデル」のどれかのクラスのフィールドを、データベースに格納する前に参照し、何らかの形で利用する場合、独自の入力検査ロジックを書く必要がある。

e) Taint機能

Ruby 言語には Taint 機能が備わっている。Taint 機能とは、オブジェクトにマークをつけ、信頼できない入力値の伝播を追跡できる仕組みである。

Ruby on Rails 自体は Taint 機能を利用していないが、Taint 機能を用いたプラグインをつくることが可能である。

Ruby on Rails 2 用には、Taint 機能を利用したスクリプト注入(XSS)対策プラグインとして SafeERB というものが存在している。

f) ユーザ認証

  

Ruby on Rails 本体には、ユーザ認証の仕組みは用意されていない。しかし、ユーザ認証のための複数のプラグインがサードパーティから提供されている。

サードパーティによるユーザ認証プラグインの例

  • Devise
  • Authlogic
  • Restful authentication
  • Clearance
  • Rails OpenID 等

g) アクセス認可

Ruby on Rails 本体には、アクセス認可の仕組みは用意されていない。しかし、アクセス認可のための複数のプラグインがサードパーティから提供されている。

(1) 所有者やロールによる認可

情報の所有者やロールにもとづくアクセス認可のプラグインには、例えば、CanCan、declarative_authorization、grant 等がある。

コード CanCanの権限記述例
  # models/ability.rb
  class Ability
    include CanCan::Ability
    
    def initialize(user)
      user ||= User.new # guest user
      
      if user.role? :admin
        can :manage, :all
      else
        can :read, :all
        can :create, Comment
        can :update, Comment do |comment|
          comment.try(:user) == user || user.role?(:moderator)
        end
        if user.role?(:author)
          can :create, Article
          can :update, Article do |article|
            article.try(:user) == user
          end
        end
      end
    end
  end

出典 http://railscasts.com/episodes/192-authorization-with-cancan

(2) ログインによる保護

未ログイン者からコンテンツを保護するしくみは、ユーザ認証プラグインがサポート していることが多い。

(3) before_filter によってコンテンツを保護する

Ruby on Rails アプリケーションの「コントローラ」クラス群(HTTPリクエストに応じた処理を行う)では、before_filter という指令が使える。

これは、「コントローラ」クラス群のビジネスロジックが呼び出される前に、何らかのフィルタ処理メソッドの呼び出すよう定義するものである。

これを用いると、ビジネスロジックとアクセス認可のためのコードをきれいに分離して配置できる。

ユーザ認証やアクセス認可のプラグインの多くは、これを利用している。


フレームワークの選択

Webアプリケーションフレームワークは、アプリケーションプログラミングの負担を軽減してくれるのみならず、セキュアプログラミングに役立つ機能も備えはじめている。また、フレームワークが、どのような脆弱性に自動で対策を施してくれ、どの問題についてはプログラマによる対処が必要かは、製品、バージョンによって様々である。

フレームワークを利用する際は、それらの点を見極めた上で、必要な脆弱性予防策を講じることが重要である。