FuelPHPのAjaxでのCSRF対策

AjaxというかJavaScriptでのCSRF対策用のSecurity::js_fetch_token()メソッドがFuelPHPにはあって、ビューで

<?php
echo Security::js_fetch_token();
?>

とやると、CSRF対策のワンタイムトークンを取得するfuel_csrf_token()関数がJavaScriptで使えるようになります。

なので、デフォルトではfuel_csrf_tokenというキーでトークンをPOSTします。例えば、jQueryだと以下のようなコードになり、

$.post(
    '/post/create',
    {
        content: data,
        fuel_csrf_token: fuel_csrf_token()
    }
)
…略…

コントローラでは、普通にSecurity::check_token()メソッドでトークンをチェックすればいいです。

if (! Security::check_token()) {
    // トークンエラー
}

POSTじゃない場合も、トークンを抽出して

if (! Security::check_token($token)) {
    // トークンエラー
}

のように受け取ったトークンを引数に渡せばOKです。

ところで、Security::js_fetch_token()メソッドの生成するコードは、以下のようになっています。

<script type="text/javascript">
function fuel_csrf_token()
{
    if (document.cookie.length > 0)
    {
        var c_name = "fuel_csrf_token";
        c_start = document.cookie.indexOf(c_name + "=");
        if (c_start != -1)
        {
            c_start = c_start + c_name.length + 1;
            c_end = document.cookie.indexOf(";" , c_start);
            if (c_end == -1)
            {
                c_end=document.cookie.length;
            }
            return unescape(document.cookie.substring(c_start, c_end));
        }
    }
    return "";
}
</script>

Cookieからトークンの値を取得しています。なので、HttpOnlyなCookieだとJavaScriptからはトークンを取得できなくなり使えません。

なんかちょっと微妙なんですが、FuelPHPのCSRF対策のトークンはワンタイムトークンのためAjaxリクエストごとに値が変わります。連続してAjaxリクエストを送る可能性がある場合、他にうまく新しいトークンを取得する方法を思い付きません。

ワンタイムトークンをやめないと無理な気がします。

関連

Tags: fuelphp, csrf, ajax

Phalcon Forum(Phosphorum)を動かしてみる

この記事はPhalcon Advent Calendar 2014の19日目です。昨日はyohgakiさんの「速いアプリケーションの作り方」でした。

Phalconの公式フォーラムのソースコードは公開されています。

今日はこのフォーラムを動かしてみたいと思います。

ソースコードのインストールと仮想マシンの作成

ソースコードは一部不具合がありましたので、forkして修正したものを使います。

$ git clone git@github.com:kenjis/phalcon-forum.git

vagrant-centos6-phpをcloneします。

$ cd phalcon-forum/
$ git clone git@github.com:kenjis/vagrant-centos6-php.git

vagrant-centos6-php/Vagrantfileを変更します。

--- a/Vagrantfile
+++ b/Vagrantfile
@@ -83,10 +83,10 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
      #chef.add_recipe "phpmyadmin"

      chef.add_recipe "git"
-     #chef.add_recipe "beanstalkd"
+     chef.add_recipe "beanstalkd"
      #chef.add_recipe "mongodb"
      #chef.add_recipe "redis"
-     #chef.add_recipe "elasticsearch"
+     chef.add_recipe "elasticsearch"

      chef.add_recipe "phpunit"
      chef.add_recipe "php-project"
@@ -94,7 +94,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
      # Framework of your choice
      #chef.add_recipe "codeigniter"
      #chef.add_recipe "fuelphp"
-     #chef.add_recipe "phalcon"
+     chef.add_recipe "phalcon"

      #chef.add_recipe "yum-update"

仮想マシンを構築します。

$ cd vagrant-centos6-php/
$ vagrant up

GitHubの設定

GitHubにPhalcon Forum用のOAuth Applicationを登録します。

GitHubでSettingsからApplicationsを選び、Developer applicationsの「Register new application」ボタンを押します。

▼Phalcon Forum用の設定を入力します。 GitHubアプリケーションの登録

「Authorization callback URL」はhttp://localhost:8000/login/oauth/access_token/と入力します。

▼登録が完了するとClient IDとClient Secretが表示されます。 GitHubのアプリケーションの設定

Composerパッケージのインストール

仮想マシンにSSH接続し、Composerのパッケージをインストールします。

$ vagrant ssh

以下は仮想マシン上です。

[vagrant@localhost ~]$ cd phalcon
[vagrant@localhost phalcon]$ composer install

Phalcon Forumの設定

app/config/config.example.phpapp/config/config.phpにコピーします。

$ cp app/config/config.example.php app/config/config.php

app/config/config.phpにデータベース接続、GitHubのApplication、SMTPサーバ、メールアドレスなどを設定します。

--- config.example.php  2014-11-29 10:28:57.000000000 +0900
+++ config.php  2014-12-17 19:09:53.000000000 +0900
@@ -30,7 +30,7 @@
         'adapter'  => 'Mysql',
         'host'     => 'localhost',
         'username' => 'root',
-        'password' => '',
+        'password' => 'root',
         'dbname'   => 'forum',
         'charset'  => 'utf8'
     ),
@@ -57,9 +57,9 @@
     ),

     'github'      => array(
-        'clientId'     => '',
-        'clientSecret' => '',
-        'redirectUri'  => 'http://pforum.loc/login/oauth/access_token/'
+        'clientId'     => '0a84ac3e3491d8ca1c50',
+        'clientSecret' => '731710866a00fb65ee2250965ed5e53b5fe2095b',
+        'redirectUri'  => 'http://localhost:8000/login/oauth/access_token/'
     ),

     'amazonSns'   => array(
@@ -67,15 +67,15 @@
     ),

     'smtp'        => array(
-        'host'     => "",
+        'host'     => "localhost",
         'port'     => 25,
-        'security' => "tls",
+        'security' => "",
         'username' => "",
         'password' => ""
     ),

     'beanstalk'   => array(
-        'disabled' => true,
+        'disabled' => false,
         'host'     => '127.0.0.1'
     ),

@@ -85,6 +85,6 @@

     'mail'     => array(
         'fromName'     => 'Phalcon',
-        'fromEmail'    => 'phosphorum@phalconphp.com',
+        'fromEmail'    => 'MyAddress@example.jp',
     )
 ));

データベースの作成

データベースforumを作成し、テーブルを作成します。

[vagrant@localhost phalcon]$ echo 'CREATE DATABASE forum CHARSET=utf8 COLLATE=utf8_unicode_ci' | mysql -u root -proot
[vagrant@localhost phalcon]$ cat schemas/forum.sql | mysql -u root -proot forum

ダミーデータの挿入

ダミーデータをFakerで作成するスクリプトが付属していますので、実行します。

[vagrant@localhost phalcon]$ php scripts/random-entries.php

これで、ダミーデータが挿入されました。

http://localhost:8000/にアクセスしてみます。

▼Forumのトップページが表示されました。 Phalcon Forum

ファンクショナルテスト

一応Codeceptionによるファンクショナルテストが付属していますので、実行してみます。

[vagrant@localhost phalcon]$ php codecept.phar run
Codeception PHP Testing Framework v2.0.8
Powered by PHPUnit 4.3.5 by Sebastian Bergmann.

Functional Tests (3) ---------------------------------------------------------------------------------------
Trying to reply in a discussion (ReplyInDiscussionCept)                                                Ok
Trying to perform shadow login as first user (ShadowLoginCept)                                         Ok
Trying to start a discussion (StartDiscussionCept)                                                     Ok
------------------------------------------------------------------------------------------------------------

Unit Tests (0) ------------------------------
---------------------------------------------


Time: 3.15 seconds, Memory: 23.50Mb

OK (3 tests, 8 assertions)

テストが通りました。

ログインしてみる

「Login with Github」ボタンを押して、ログインしてみます。

▼GitHubのアプリ承認ページに飛びました。 Phalcon Forum

▼ログインできました。 Phalcon Forum

メールの送信

Phalcon Forumでは、投稿通知のメール送信ジョブがBeanstalkdにキューイングされるようになっています。

Phalcon Forumの設定で、beanstalkddisabledfalseに変更しましたので、すでにダミーデータの挿入時の投稿がBeanstalkdにキューイングされています。

ジョブを処理するには以下のスクリプトを実行します。

[vagrant@localhost phalcon]$ php scripts/send-notifications-consumer.php &

これでメールがどんどん送信されます。

この仮想マシンではメールはすべてMailCatcherにキャッチされ、外部には一切送信されないようになっています。

http://localhost:1080/にアクセスすると、MailCatcherがキャッチしたメールを閲覧できます。

MailCatcher

検索インデックスの作成

以下のスクリプトを実行すると、すべての投稿をElasticsearchにインデックスします。

[vagrant@localhost phalcon]$ php scripts/search-tasks.php

スクリプト実行中は、以下のようなインデックスされた情報が出力されます。

array(5) {
  '_index' =>
  string(10) "phosphorum"
  '_type' =>
  string(4) "post"
  '_id' =>
  string(8) "post-501"
  '_version' =>
  int(1)
  'created' =>
  bool(true)
}

これで、検索可能になりました。

▼「llc」という文字列を検索してみます。 MailCatcher

▼検索されました。 MailCatcher

この記事はPhalcon Advent Calendar 2014の19日目です。明日は、MiuraKatsuさんの「transifex - ボクがPhalcon翻訳プロジェクトでやらかしたコト」です。

関連

Tags: phalcon, oauth, beanstalkd, codeception, elasticsearch, database

Phalconのチュートリアル(チュートリアル 1)の最新ソースを見てみる

Phalconのチュートリアル(チュートリアル 1)」は、GitHubにリポジトリがあります。

一応、最新のソースコードを確認しておきます。

主要な変更点

まあ、大きな変更はもちろんないんですが、1つだけビューでのTagヘルパーの書き方が変わってました。

--- a/app/views/index/index.phtml
+++ b/app/views/index/index.phtml
@@ -1,4 +1,4 @@
 <?php
 echo "<h1>Hello!</h1>";

-echo Phalcon\Tag::linkTo("signup", "Sign Up Here!");
+echo $this->tag->linkTo("signup", "Sign Up Here!");
--- a/app/views/signup/index.phtml
+++ b/app/views/signup/index.phtml
@@ -1,8 +1,6 @@
-<?php use Phalcon\Tag; ?>
-
 <h2>Sign up using this form</h2>

-<?php echo Tag::form("signup/register"); ?>
+<?php echo $this->tag->form("signup/register"); ?>

 <!-- CSRF対策のトークン -->
 <input type="hidden" name="<?php echo $this->security->getTokenKey() ?>"
@@ -10,16 +8,16 @@

  <p>
     <label for="name">Name</label>
-    <?php echo Tag::textField("name") ?>
+    <?php echo $this->tag->textField("name") ?>
  </p>

  <p>
     <label for="email">E-Mail</label>
-    <?php echo Tag::textField("email") ?>
+    <?php echo $this->tag->textField("email") ?>
  </p>

  <p>
-    <?php echo Tag::submitButton("Register") ?>
+    <?php echo $this->tag->submitButton("Register") ?>
  </p>

 </form>

それと、HTTPヘッダに文字コードの指定が追加されてました。

--- a/public/.htaccess
+++ b/public/.htaccess
@@ -1,3 +1,4 @@
+AddDefaultCharset UTF-8
 <IfModule mod_rewrite.c>
     RewriteEngine On
     RewriteCond %{REQUEST_FILENAME} !-d

関連

Tags: phalcon