.ログイン
ユーザ名:

パスワード:


パスワード紛失

新規登録

.検索

.メインメニュー

.フォーラムメニュー

.オンライン状況
14 人のユーザが現在オンラインです。 (13 人のユーザが フォーラム を参照しています。)

登録ユーザ: 0
ゲスト: 14

もっと...

.
.リンク集

メイン
   helper,component,script
     クロスサイトリクエストフォージェリ対策
投稿するにはまず登録を

スレッド表示 | 新しいものから 前のトピック | 次のトピック | 下へ
投稿者 スレッド
shun
投稿日時: 2006-12-15 23:00
Cake 職人
登録日: 2006-7-14
居住地: 東京、日本
投稿: 1007
クロスサイトリクエストフォージェリ対策
CSRFって何?という話はこちらが詳しいです。
http://www.atmarkit.co.jp/fsecurity/column/ueno/33.html

Shin さんがCakePHPでのサンプルコードを掲載されています。

CakePHPでCSRF対策
http://www.1x1.jp/blog/2006/12/cakephp_csrf.html
nakade
投稿日時: 2006-12-16 10:15
Baker スタート
登録日: 2006-12-15
居住地:
投稿: 15
Re: クロスサイトリクエストフォージェリ対策
引用:

私も上記URLと同様の方法でCSRF対策をしていたのですが、
同一ページに複数フォームを設置する必要があり、
困っています。(複数フォームだと、クッキーに保存され
るtokenは1つのフォームのtokenと同じで、他のフォームが
もつtokenの値とは異なる)

複数フォームの場合、無理なんでしょうか?
なにか良い案があれば教えてください。
shun
投稿日時: 2006-12-16 11:51
Cake 職人
登録日: 2006-7-14
居住地: 東京、日本
投稿: 1007
Re: クロスサイトリクエストフォージェリ対策
ヒントくらいですが、

HtmlHelper の formTag() では、

<?php
if (isset($this->params['_Token']) && !empty($this->params['_Token'])) {
                
$token $this->hidden('_Token/key', array('value' => $this->params['_Token']['key']), true);
        }

        return 
sprintf($this->tags['form'], $this->parseHtmlOptions($htmlAttributesnull'')) . $token;
?>



とやって出力しているようです。$this->params['_Token'] に値があるかないかを調べてから、$this->params['_Token']['key']の値を出力しています。

また、cake\libs\components\security.php の中を読むと、startup() の中で、


<?php
// Add auth key for new form posts
        
$authKey Security::generateAuthKey();
        
$expires strtotime('+'.Security::inactiveMins().' minutes');
        
$token = array(
            
'key' => $authKey,
            
'expires' => $expires,
            
'allowedControllers' => $this->allowedControllers,
            
'allowedActions' => $this->allowedActions
        
);
        if (!isset(
$controller->params['data'])) {
            
$controller->params['data'] = array();
        }
        
$controller->params['_Token'] = $token;
        
$this->Session->write('_Token'$token);
?>


とやっています。$this->Session->write('_Token', $token); とやっているので、ここからセッションのキーとデータの取り出し方が分かります。

このあたりを自分のビューの中で操作できると思います。または複数のキーを保存したいのであればコントローラで保存したりしておくと、期待どおりの動きができるように思いますが、いかがでしょうか。
nakade
投稿日時: 2006-12-20 9:38
Baker スタート
登録日: 2006-12-15
居住地:
投稿: 15
Re: クロスサイトリクエストフォージェリ対策
引用:

shunさんは書きました:

複数のキーを保存したいのであればコントローラで保存したりしておくと、期待どおりの動きができるように思いますが、いかがでしょうか。



コントローラで保存するとはどのような感じでしょうか?
もうすこし具体的に教えていただけないでしょうか?
shun
投稿日時: 2006-12-20 18:48
Cake 職人
登録日: 2006-7-14
居住地: 東京、日本
投稿: 1007
Re: クロスサイトリクエストフォージェリ対策
nakadeさんの投稿で、何をしたいと思っているのかがよく理解できていませんでした。ビューの概要だけでもコードを貼り付けてもらえますか?
(二つのフォームを1枚に貼り付ける必要がある理由を説明していただけますか?それによってコードも変わると思います。)

引用:

同一ページに複数フォームを設置する必要があり、
困っています。(複数フォームだと、クッキーに保存され
るtokenは1つのフォームのtokenと同じで、他のフォームが
もつtokenの値とは異なる)
複数フォームの場合、無理なんでしょうか?


ちなみに、同一ページに formTag() を2回使って二つのフォームを設置した場合、「クッキーに保存されるtokenは1つのフォームのtokenと同じ」で、「他のフォームがもつtokenの値」も、そのクッキーに保存されるtokenと同じです。

つまり標準の動作では、どちらのフォームにも「同じtokenの値」が書き込まれています。なので通常はこのままでうまく動くのではないでしょうか。小細工が必要であれば、それもまた可能だと思いますが……。
nakade
投稿日時: 2006-12-21 17:13
Baker スタート
登録日: 2006-12-15
居住地:
投稿: 15
Re: クロスサイトリクエストフォージェリ対策
説明不足ですみません。m(__)m
viewは以下のような内容です。


●登録フォーム
<?php echo $html->formTag('/hoge/add/'); ?>
<?php echo $html->submit('登録') ?>
</form>

●コメントフォーム
<span id=cmtForm></span>

<script>
<!--
<?php echo  $ajax->remoteFunction(array('update'=>'cmtForm','url'=>'/cmt/')); ?>
//-->
</script>


コメントフォームについては、ページの表示をかえたくなかった
ので、ajaxで出すようにしています。

この場合、それぞれのフォームに違ったTokenがはいってしまう
ので、困っていました。

以上、よろしくお願いします。
shun
投稿日時: 2006-12-21 21:53
Cake 職人
登録日: 2006-7-14
居住地: 東京、日本
投稿: 1007
Re: クロスサイトリクエストフォージェリ対策
なるほど。何回呼ばれるか分からない Ajax コールでは単純に解決できませんね。

英語のMLでは過去にいくつかその話題で話がありました。

1) ワンタイムトークンを使わない方法
セキュリティコンポーネントは、主に外部からの不正なリクエストをはじくためのものなので、Ajaxの時にはバイパスする、というもの。

Usability of component 'Security'
http://groups-beta.google.com/group/cake-php/browse_thread/thread/917290f79bd20cf5/

ここでは、

<?php
function beforeFilter( ) { 
    if (
$this->params['bare'] == && !in_array($this->action
array(
'ここに''許可された''アクション'))) { 
        
$this->Security->blackHole(); 
    }
?>


のような形で、ajaxコールであれば、公開されているアクションだけが動くようにする、というのが提案されています。

2) ワンタイムトークンを使う方法
Security component - multiple tabs and AJAX problem
http://groups-beta.google.com/group/cake-php/browse_thread/thread/3c77e3e05ba4a2d7/

ここでは、
getToken()
updateToken()
という関数を準備して、submit する前に JavaScriptを読んで、トークンの値を最新のものに書き換えればいいのではないか、というアイデアが出ています。Ticket もこちらに

http://groups-beta.google.com/group/tickets-cakephp/browse_thread/thread/cac755b6abc2480e/

出ていました。これなら、複数ブラウザを立ち上げても大丈夫なのではないか、ということです。

ちなみに Symfony の文書では、
http://develop.ddo.jp/tech/index/PHP/Symfony/documentation/Symfony101/%A5%EA%A5%B9%A5%C8%A4%F2%CA%C2%A4%D3%C2%D8%A4%A8%A4%C7%A4%AD%A4%EB%A4%E8%A4%A6%A4%CB%A4%B9%A4%EB%CA%FD%CB%A1#va42380f
Ajaxコールの“後に”不正なリクエストではないか、チェックさせるアイデアが書いてありますね。

(Piece Framework ではこのあたりを今後、どう解決するんでしょうか……。)
shun
投稿日時: 2006-12-21 23:05
Cake 職人
登録日: 2006-7-14
居住地: 東京、日本
投稿: 1007
Re: クロスサイトリクエストフォージェリ対策
そういえば一番簡単なのは、ajaxのフォームを formTag()を使わないで書くことですね。そうすれば“トークン問題は”起きませんね……。

セキュリティを完璧に追求したいようであれば、

<?php
$this
->Session->write('_Token'$token);
?>




<?php
$this
->Session->write('_AjaxToken'$token);
?>



にした、"AjaxSecurity"コンポーネントを作って、AjaxFormTag() なんて作ってもいいかもしれませんね。
nakade
投稿日時: 2006-12-22 10:36
Baker スタート
登録日: 2006-12-15
居住地:
投稿: 15
Re: クロスサイトリクエストフォージェリ対策
引用:

getToken()
updateToken()
という関数を準備して、submit する前に JavaScriptを読んで、トークンの値を最新のものに書き換えればいいのではないか、というアイデアが出ています。Ticket もこちらに

http://groups-beta.google.com/group/tickets-cakephp/browse_thread/thread/cac755b6abc2480e/

出ていました。これなら、複数ブラウザを立ち上げても大丈夫なのではないか、ということです。


上記、いいですね。
問題が解決できそうです。
このticketが取り入れられば入れ替えるとして、
とりあえず、現状では、以下でいこうかなぁと思います。

引用:

"AjaxSecurity"コンポーネントを作って、AjaxFormTag() なんて作ってもいいかもしれませんね。


いろいろとありがとうございました。
aska
投稿日時: 2007-6-21 16:45
Baker スタート
登録日: 2007-6-21
居住地:
投稿: 1
POST時必ずチェックされる仕様について
現在 1.2.0.5137alpha を利用しています、

下記の様な画面遷移(参照1)にて、
Securityコンポーネントを使用し、
確認 => 完了 の遷移時にTokenのチェックを行いたいと考え、
Controllerに(参照2)の様にコードを追加しました。

■ 画面遷移(参照1)

・トップページ
  ↓(GET)
・入力画面
 ↑↓(POST,Tokenチェックしたくない)
・確認画面
  ↓(POST,Tokenチェックしたい)
・完了画面

■ Controller(参照2)
/app/controllers/posts_controller.php

<?php
var $components = array('Security');
    
    function 
beforeFilter()
    {
        
$this->requirePost('end');
        
$this->requireAuth('end');
    }
    function 
frm()
    {
    }
    
    function 
confirm()
    {
    }
    
    function 
end()
    {
    }
?>



ところが、入力 => 確認の遷移でTokenのチェックが行われ、弾かれてしまいます。
ソースコードを追った所、(参照3)で__validatePostが呼ばれ、
このコード内でのTokenのチェックで弾かれていたようです。

requirePostにもrequireAuthにも指定していないアクションでも
POSTでリクエストを受け付けると必ずTokenチェックが走るようです。

この仕様で困るのは、入力=>確認の様なブラウザの[戻る]で戻って
送信し直しても良いような緩い遷移でも、
画面上のボタンで移動しないといけなくなってしまう事です。
皆様は如何しておりますでしょうか。

■ Security(参照3)
/app/cake/libs/controller/components/security.php line 143

<?php
function startup(&$controller) {
        
$this->__postRequired($controller);
        
$this->__secureRequired($controller);
        
$this->__authRequired($controller);
        
$this->__loginRequired($controller);

        
// POST時チェックされる
        
if((!isset($controller->params['requested']) || $controller->params['requested'] != 1) && $this->RequestHandler->isPost()) {
            
$this->__validatePost($controller);
        }

        
$this->__generateToken($controller);
    }
?>

スレッド表示 | 新しいものから 前のトピック | 次のトピック | トップ

投稿するにはまず登録を
 


. .