ANNAIマガジン
CSRF
この記事の目次

クロスサイトリクエストフォージェリー(CSRF)はDrupalにおける一般的な脆弱性ですが、これを防ぐ事はさほど難しい事ではありません。この記事では、開発者がまず適切で安全なコードを書けるようになること、そして既存のコードに見つかった場合に脆弱性を修正できることを目的としています。

まず、CSRFについて理解する必要があります。詳しくは、クロスサイトリクエストフォージェリーとは?をご覧ください。

DrupalのCSRFに対するフォームの使用

開発者は(2006年5月の)Drupal 4.7のリリース時点で、フォームの作成、検証、送信処理の中心となるDrupalコアのForm APIを使用しています。その作成と検証の一部は、フォーム送信時に特別なトークンがユーザーに送信され、検証されるように保証することです。 Drupalは、少なくとも以下の3つの値で構成されるハッシュを使用します。

  • ユーザーセッションID
  • 実行されるアクションに関連付けられた文字列
  • サイトに対してプライベートな文字列


攻撃者がこのトークンを解析できれば、そのトークンをリクエストに追加する事で、サイトで強制的にアクションを実行させることができます。幸いにも、この情報を簡単に解析することはできません。 (トークンを解析するには、多くのコンピュータリソースと、セッションの固定などのさらなる弱点が必要になります。しかし、こういった事はほとんどありません。)

実際にフォームを作成する際には Forms APIクイックスタート・ガイドを参考にしてください。サイト上のデータ変更を伴う、あらゆるアクションにフォームを使用することでCSRFを防ぐことができます。

デザインやユーザーインターフェイスの都合上フォームが機能しない場合があり、代わりにとして、小さなリンクが必要となる場合もあります。ユーザーの削除やコンテンツの削除など、潜在的に破壊的な操作のリンクを使用する場合には、確認フォームを使用して、ユーザーがアクションを実行していることを確認する必要があります。

注意

ユーザビリティの改善に関わる人々は、確認フォームを使用すべきではないと言います。これは確かにユーザービリティの観点から言えば正しいと言えます。彼らの懸念としては、確認フォームを使用すると、フォーム入力時の流れがスムーズでなくなる事です。この解決策としては、簡単に取り消し可能な方法でデータを保存することです。

実際に確認フォームをどのように作成したら良いでしょうか?とても良い例として、 User protectモジュールのコードをご覧下さい。このパッチから実例学ぶことができます。

トークンを直接利用することでDrupalのアクションを保護する

実行しようとしているアクションが削除ほど重大でない場合はどうした良いでしょうか?

その場合、Drupalのトークン生成を直接利用するという別の方法を使用することができます。 良い例として、Security Reviewモジュールのコードをご覧ください。

security_review_reviewed ファンクション内のリンクにトークンを追加します。


   $token = drupal_get_token($check['reviewcheck']);
    $link_options = array(
      'query' => array('token' => $token),
      'attributes' => array('class' => 'sec-rev-dyn'),
     );


そのトークンはsecurity_review_toggle_checkでチェックされます:


   if (!drupal_valid_token($_GET['token'], $check_name)) {
      return drupal_access_denied();
    }


さまざまな方法でトークンをリンクに挿入し、AJAXコードを記述してリクエストを送信し、リクエストを検証することができます。 基本的な考え方は、アクションのリクエストと共に返されるトークンをページに追加し、アクションを実行される前にトークンを検証することです。

注意

多くの人は、サイト上でリンクに応答するアクションを実行する事は不適切だと思うのではないでしょうか。(それはPOSTリクエストとは対照的にHTTP GETリクエストを開始します。これは、一般的にフォーム内で使用され、サーバー上でデータを変更する際のHTTP仕様として定義されます。)

また、ページ内の全てのリンクを先読みするHTTPアクセラレーターのようなリンクを利用する場合に潜在的な問題となります。 リンクにrel = "nofollow"属性を追加することで、先読みを軽減できますが、先読みは最近ではあまり利用されることが少なくなってきているので、場合によっては対処する必要はないかもしれません。

終わりに

この記事で解説されているように Form API を適切に利用すれば簡単な実装でCSRF対策を行えます。

システム管理者向けのフォームを生成する場合は、 system_settings_form を使うことにより drupal_get_token/drupal_set_token を直接呼び出すことなくフォームを保護できます。

逆に、テンプレートにformタグ全体を直接マークアップするような実装は、脆弱性を引き起こす可能性があるので注意が必要です。

 
フッターの採用情報
 
Yoshikazu Aoyamaの写真

この記事を書いた人: Yoshikazu Aoyama

昔は回線交換やL2/L3のプロトコルスタックの開発をしてました。その後、組み込みLinuxやJava/Ruby on RailsなどのWebシステム開発などを経て現職。
インフラからDrupalのモジュール開発、Drupal以外の開発までなんでもやります。
普段は札幌で猫と一緒にリモートワークしています。 好きなモジュールは Restful Web Services と Rules

関連コンテンツ