1

フォームのレンダリングごとに CSRF トークンを生成する方法が Symfony 2 に存在しますか? 私のコントローラーでは、次のようなことを試しました:

$request = $this->get('request');
    if ($request->getMethod() != 'POST') {
        $csrf = $this->get('form.csrf_provider');
        $date= new \DateTime("now");
        $this->date = $date->format('Y-m-d H:i:s');
        $token = $csrf->generateCsrfToken($this->date);
    } elseif($request->getMethod() == "POST") {
        $csrf = $this->get('form.csrf_provider');
        $token = $csrf->generateCsrfToken($this->date);
    }

    $form =  $this->createFormBuilder()
    ....
    ->add('_token','hidden',array(
        'data' => $token
        ))->getForm();

    if ($request->getMethod() == 'POST') {
        $form->bindRequest($request);

        if ($form->isValid()) {
            DO something
        }
    }

すべての時間は、私の要求の正しいトークン ハッシュにあります。しかし、bindRequest の後、parameters.ini のセキュリティ文字列と isValid メソッドから生成されたデフォルト ハッシュへの変更は、確実に FALSE 応答を返します。何らかの方法で存在しますが、それを調整するにはどうすればよいですか?

編集 アンラベラーの回答に応えて、コントローラーを編集してCSRFプロバイダーを作成しましたが、「CSRFトークンが無効です。フォームを再送信してください」というエラーが表示されます。私の CSRF プロバイダーは次のようになります。

namespace My\Namespace;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;

class MyCsrfProvider implements CsrfProviderInterface
{
    protected $session;
    protected $secret;
    protected $datetime;

    public function __construct(Session $session, $secret)
    {
        $this->secret = $secret;
        $this->datetime = new \DateTime('now');
        $this->session = $session;
    }

    public function generateCsrfToken($intention)
    {
        return sha1($this->secret.$intention.$this->datetime->format('YmdHis').$this->getSessionId());
    }

    public function isCsrfTokenValid($intention, $token)
    {
        return $token === $this->generateCsrfToken($intention);
    }

    protected function getSessionId()
    {
        return $this->session->getId();
    }
}

config.yml サービス クラスに追加するよりも:

services:
form.csrf_provider: 
    class: My\Namespace\MyCsrfProvider
    arguments: [ @session, %kernel.secret% ]

そしてコントローラーはこれに変更します:

//any form without _token field
    $form =  $this->createFormBuilder()
        ->add('field1')
        ->add('field2')->getForm()

        if ($this->getRequest()->getMethod() == 'POST') {

            $request = $this->getRequest();
            $form->bindRequest($request);

            if ($form->isValid()) {
                Do something
                return $this->redirect($this->generateUrl('somewhere'));
            }
        }

私のハッシュで数秒で問題になることはありませんか? 日時形式から秒を削除すると機能しますが、有効期限が 1 分であり、良い解決策ではありません。理由は、時代が変わったからだと思います。

4

2 に答える 2

1

Symfony のFormコンポーネントは、フォーム イベントで CSRF トークンを生成します。Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener既存の実装がどのように機能するかについては、クラスを参照してください。つまり、フォームでbindRequest()(またはbind()Symfony 2.2+ で) 呼び出すと、そのフォーム イベントが呼び出され、宣言したトークンが上書きされます。

別のトークンを定義する正しい方法は、 を作成することです。CsrfProviderこれは、基本的には を実装するクラスを作成しますSymfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface。これを実装する方法の例については、Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProviderを確認してください。

クラスを記述したら、app/config/parameters.yml(または別の構成ファイル、場所は関係ありません) で、form.csrf_provider.classパラメーターをクラスの名前に設定します。

その後、コントローラーから作成したすべてのカスタム コードを削除し、フォーム システムを何も変わらないかのように使用する (つまり、->add('_token')...パーツを削除する) ことができるはずです。

それが役立つことを願っています!

于 2013-04-10T06:03:49.180 に答える
-1

知っていform_restますか?これをフォームの一番下に追加して、CSRF トークンを自動的に生成します。

{{ form_rest(form) }}
于 2013-04-08T21:34:17.323 に答える