2

コントローラで追加、更新、削除のアクション用のフィルタを作成して、それらが自動的にチェックされるかどうかを確認したい

  1. GETやその他のメソッドではなく、POSTで呼び出されました
  2. ビューのフォームに設定したpageInstanceIDを持っています
    • xssから保護します
    • フォームの二重送信から保護します
      • 送信ボタンからダブルクリック
      • 提出後に押された戻るボタンから
      • 保存またはブックマークされているURLから

現在、AppControllerを使用して\ lithium \ action \ Controllerを拡張し、そこで追加、更新、および削除のアクションを定義しています。AppControllerには、適切なpageInstanceIDがセッションにあるかどうかをチェックするブール関数もあります。

以下は私のコードです:

public function isNotPostBack() {

    // pull in the session
    $pageInstanceIDs = Session::read('pageInstanceIDs');
    $pageInstanceID = uniqid('', true);
    $this->set(compact('pageInstanceID'));
    $pageInstanceIDs[] = $pageInstanceID;
    Session::write('pageInstanceIDs', $pageInstanceIDs);

    // checks if this is a save operation
    if ($this->request->data){

        $pageInstanceIDs = Session::read('pageInstanceIDs');
        $pageIDIndex = array_search($this->request->data['pageInstanceID'], $pageInstanceIDs);

        if ($pageIDIndex !== false) {
            // remove the key
            unset($pageInstanceIDs[$pageIDIndex]);
            Session::write('pageInstanceIDs', $pageInstanceIDs);

            return true;

        }
        else
            return false;

    } else {
        return true;
    }

}

public function add() {
    if (!$this->request->is('post') && exist($this->request->data())) {
        $msg = "Add can only be called with http:post.";
        throw new DispatchException($msg);
    }

}

次に、コントローラーでAppControllerから継承し、次のようなアクションを実装します。

public function add() {
    parent::add();
    if (parent::isNotPostBack()){
        //do work

    }
    return $this->render(array('layout' => false));

}

これにより、フォームがPOSTを使用し、二重に送信されていないことが保証されます([戻る]ボタンまたは[ハッピーユーザー]をクリックします)。これは、XSSからの保護にも役立ちます。

このためのプラグインがあることは知っていますが、コントローラーメソッドがよりクリーンになるように、これをフィルターとして実装したいと思います。このように、私のアクションのコードは//dowork部分とreturnステートメントだけです。

4

4 に答える 4

2

まず、統合CSRF(XSRF)保護を使用します。

RequestTokenクラスは、クライアント要求の信頼性を検証するために使用できる暗号的に安全なトークンとキーを作成します。

http://li3.me/docs/lithium/security/validation/RequestToken

次のようにCSRFトークンを確認します。

if ($this->request->data && !RequestToken::check($this->request)) {
    /* do your stuff */
}

を介して使用されるHTTPメソッドを確認することもできますis()

$this->request->is('post');

フィルタの問題(そのユースケースの場合)は、フィルタが非常に一般的であるということです。したがって、すべてのアクションをフィルタリング可能なコードとして記述したくない場合(これは苦痛でやり過ぎかもしれません)、どのメソッドが何をブロックするかを定義し、をフィルタリングする方法を見つける必要がありますDispatcher::_call

于 2012-03-21T12:30:31.687 に答える
2

lithium\action\Dispatcher::run()おそらく、疑似コードであるフィルターから始める必要があります。メソッドを見ないとあまり役に立ちませんparent::isNotPostBack()が、これで正しい軌道に乗るはずです。

<?php
use lithium\action\Dispatcher;

Dispatcher::applyFilter('run', function($self, $params, $chain) {
    $request = $params['request'];

    // Request method is in $request->method
    // Post data is in $request->data

    if($not_your_conditions) {
        return new Response(); // set up your custom response
    }

    return $chain->next($self, $params, $chain); // to continue on the path of execution
});
于 2012-03-21T02:21:15.163 に答える
0

CSRF 保護のために、greut の提案に似たものを使用します。

私は私の中にこれを持っていますextensions/action/Controller.php

protected function _init() {
    parent::_init();

    if ($this->request->is('post') ||
        $this->request->is('put') ||
        $this->request->is('delete')) {
        //on add, update and delete, if the security token exists, we will verify the token
        if ('' != Session::read('security.token') && !RequestToken::check($this->request)) {
            RequestToken::get(array('regenerate' => true));
            throw new DispatchException('There was an error submitting the form.');
        }
    }
}

もちろん、これはファイルの先頭に以下を追加する必要があることを意味します。

use \lithium\storage\Session;
use lithium\security\validation\RequestToken;
use lithium\action\DispatchException;

これにより、CSRF を繰り返しチェックする必要がなくなりました。

于 2012-03-21T18:43:32.613 に答える
0

最近のプロジェクトで(abstract)\lithium\action\Controllerとしてサブクラス化し、ディスパッチャーがアクション メソッドを呼び出す方法としてフィルターを適用することで、似たようなものを実装しました。関連するチャンクは次のとおりです。app\controllers\ApplicationControllerinvokeMethod()

namespace app\controllers;

class ApplicationController extends \lithium\action\Controller {
    /**
     * Essential because you cannot invoke `parent::invokeMethod()` from within the closure passed to `_filter()`... But it makes me sad.
     *
     * @see \lithium\action\Controller::invokeMethod()
     *
     * @param string $method to be invoked with $arguments
     * @param array $arguments to pass to $method
     */
    public function _invokeMethod($method, array $arguments = array()) {
        return parent::invokeMethod($method, $arguments);
    }

    /**
     * Overridden to make action methods filterable with `applyFilter()`
     *
     * @see \lithium\action\Controller::invokeMethod()
     * @see \lithium\core\Object::applyFilter()
     *
     * @param string $method to be invoked with $arguments
     * @param array $arguments to pass to $method
     */
    public function invokeMethod($method, array $arguments = array()) {
        return $this->_filter(__METHOD__, compact('method', 'arguments'), function($self, $params){
            return $self->_invokeMethod($params['method'], $params['arguments']);
        });
    }
}

次に、applyFilter()内部で使用_init()して、メソッドでフィルターを実行できます。$methodすべてのフィルターをチェックインする代わりに、に変更_filter(__METHOD__, . . .)することを選択できます_filter($method, . . .)が、より一般的なフィルターを維持することを選択しました。

于 2013-04-02T20:53:25.043 に答える