技術者が紹介するNTTPCのテクノロジー
gplus はてなBookmark

セキュリティ

Webアプリケーションのセキュリティ

2017.10.03

ソフトウェアエンジニア (ネットワーク、Webシステム等)
古賀紳一郎
取得資格:ITIL version3 Foundation / Ruby Association Certified Ruby Programmer Gold

概要

Webアプリケーションの開発では、攻撃から守るためのセキュリティ実装が不可欠です。しかし、攻撃手法が多様化している昨今の状況では、自前で安全なWebアプリケーションを実装するのはコストがかかります。
そこで、セキュリティ対策の機能を提供するWebアプリケーションフレームワーク(以下、フレームワーク)を採用することがひとつの解決策となります。
本記事ではフレームワークを使ったセキュリティ実装の例を紹介します。使用するフレームワークはRuby on Rails 5.1.1(以下、Rails)です。

クロスサイトスクリプティング対策

クロスサイトスクリプティングとは

クロスサイトスクリプティング(XSS)とは、脆弱性のあるWebサイトを踏み台にして、悪意のあるプログラムを、そのサイトの訪問者に送り込む攻撃手法です。この脆弱性への対策としては、サニタイジングやセキュリティヘッダが有効です。

サニタイジング(無害化)

サニタイジングとは、Webサイトの入力フォームへの入力データから、HTMLタグ、JavaScript、SQL文などを検出し、それらを他の文字列に置き換える操作のことです。これにより、入力データ中に悪意のある処理が含まれていても、それらが解釈・実行されることを防止することができます。
例えば、攻撃者が図 1のようなフォームの入力を行い、このデータを出力する画面で何も対策されていないとします。

<図1>クロスサイトスクリプティングの例(アラート表示のスクリプト入力)

出力画面を開くと図 2のようにアラートが表示されます。

<図2>クロスサイトスクリプティング例(アラート表示)

攻撃者が図 3のような入力をした場合、出力画面を開いたユーザは攻撃者が用意したサイトに誘導されてしまいます。

<図3>クロスサイトスクリプティングの例(サイト誘導のスクリプト入力)

このようなクロスサイトスクリプティングによる攻撃を防ぐには、出力する時にデータのサニタイジング(無害化)が有効な手段となります。Railsでは特に意識しなくても自動的にサニタイジングが有効になっています。
例えば出力画面のビューが次のようなコードの場合、 <%= @issue.title %>の箇所と <%= @issue.description %>の箇所の出力は自動的にサニタイジングされます。

<table class="table">
  <thead>
    <tr>
      <th>題名</th>
      <th>説明</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><%= @issue.title %></td>
      <td><%= @issue.description %></td>
    </tr>
  </tbody>
</table>

図 4はサニタイジングの例となります。「<」「>」の文字がそれぞれ「&lt;」「&gt;」(文字実体参照)に変換されてスクリプトが実行されません。

<図4>サニタイジング(無害化)の例

セキュリティヘッダ

HTTPのレスポンスに対してセキュリティヘッダを付与することにより、クロスサイトスクリプティングの脅威を軽減することができます。
Railsの場合、ブラウザに対してクロスサイトスクリプティングのフィルタ機能の有効を促す「X-XSS-Protection:1; mode=block」が自動的に付与されます。
また、Railsではapplication.rbに設定することにより容易にヘッダを追加することができます。次の例はインラインのスクリプトの実行を抑制するための「Content-Security-Policy:default-src 'self'」を追加する設定を行っています。

module Example
  class Application < Rails::Application
    config.action_dispatch.default_headers.merge!(
      'Content-Security-Policy' => "default-src 'self'"
    )
  end
end

図 5はセキュリティヘッダの例です。X-XSS-ProtectionとContent-Security-Policyが付与されていることがわかります。

<図5>セキュリティヘッダの例

クロスサイトリクエストフォージェリ対策

クロスサイトリクエストフォージェリとは

クロスサイトリクエストフォージェリとは、攻撃者がユーザの意図しないリクエストを送信させ、Webアプリケーション側も正規のリクエストとして受理してしまう脆弱性のことです。
例えば、次のような手順でデータを登録するサイトがあるとします。

  1. ログイン認証を行い、セッションを開始。セッションIDはCookieで管理。
  2. 入力画面を表示(入力画面のGETリクエスト)
  3. 入力画面でデータを入力して送信ボタンをクリック(POSTリクエストでデータを送信)
  4. データを受理してDBに保存

Webアプリケーション側は入力画面からデータ送信を期待しているわけですが、何も対策していないと2を行わずに3と同等のPOSTリクエストを行っても受け付けてしまいます。
そこで、攻撃者は3と同等のPOSTリクエストを実行するようなサイトを用意しておきます。ユーザが1のログイン認証を行った後、攻撃者が用意したサイトにアクセスするとPOSTリクエストが実行され、Webアプリケーション側はCookieに確立済みのセッションIDがあるので正規のリクエストと判断してしまい、4の処理を実行してしまいます。

トークンの発行と検証による対策

クロスサイトリクエストフォージェリの対策は、入力画面にアクセスする度に毎回異なるトークンを発行することが有効な手段となります。 具体的には次のようになります。

  1. ログイン認証を行い、セッションを開始。セッションIDはCookieで管理。
  2. 入力画面を表示(入力画面のGETリクエスト)
    トークンを発行してhiddenフィールドとして出力する。
  3. 入力画面でデータを入力して送信ボタンをクリック(POSTリクエストでデータを送信)
    入力データと一緒にトークンも送信される。
  4. 送信されたトークンが発行したトークンと一致しているか検証する。
    一致しない場合はエラーとして処理する。
  5. データを受理してDBに保存

この場合、2の処理を行わずに3と同等のPOSTリクエストを行っても、トークンが無いもしくは不正なトークンとなるため、4でエラーとなります。
Railsの場合、コントローラにprotect_from_forgeryを記述しておくと自動的にトークンが発行され、入力値に対してトークンの検証がされます。Railsのプロジェクト作成時にapplication_controller.rbが自動作成されますが、その時点でprotect_from_forgeryが記述されています。

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
end

つまり、Railsの場合、通常は特に意識しなくてもクロスサイトリクエストフォージェリ対策が有効になっています。

検証

図 6はクロスサイトリクエストフォージェリ対策の例です。フォームにauthenticity_tokenのhiddenフィールドが自動的に追加され、トークンが発行されていることがわかります。

<図6>クロスサイトリクエストフォージェリ対策の例

図 7はトークン無しでPOSTリクエストを実行する例です。HTTPステータスコードが422(Unprocessable Entity)となり、エラーとして処理されていることがわかります。

<図7>トークン無しのPOSTリクエスト

まとめ

Railsを使ったセキュリティ実装の例を紹介しました。
Railsを使うとほとんど手間をかけずにセキュリティ実装が実現できます。本記事では触れませんでしたが、Cookieにセキュア属性の付与やSQLインジェクション対策も容易に実現することが可能です。自前でセキュリティ実装を実現する場合と比べると、大幅なコスト削減効果が期待できます。
Webアプリケーションフレームワークは、実装する機能、開発者のスキル、パフォーマンス等を考慮して選定すると思いますが、セキュリティ実装のしやすさも選定する上で重要な観点です。