2016-03-24 22 views
0

私は、フォームの外にあるリンクがあり、AngularコントローラがデータをポストするYiiアプリケーションを持っています。問題は、YiiがCSRFトークンを検証しないときです。Yii 1.1.17:Angular Controller経由のPOSTでCSRFトークンの検証が失敗する

私の生のURLは次のようになります。 POST request via ajax

notificationsService.markAllAsRead = function (user_id, csrf) { 
     var dataObject = { 
      user_id: user_id, 
      YII_CSRF_TOKEN: csrf 
     }; 

     $http.post("/api/notifications/readAll", dataObject).success(function (data) { 
      return data; 
     }); 
    }; 

POSTリクエストがこのliekなります

<a id="yt1" href="#" ng-click="markAllAsRead(23, '1eb4e3ac755e22939a0fc8d5ea0e9bacb453319a')" title="Read All" tooltips-size="small" tooltips="1" class="notification-tool ng-isolate-scope"><i class="fa fa-eye"></i></a> 

マイ角度コントローラは、このように見える角度サービスを呼び出しますCSRF検証を無効にすると、呼び出しは成功します。

アイデア?

ありがとうございます!

完全な答えは:

は、いくつかの調査の後、私は角度がデータを投稿したにもかかわらず、$_POST(ものYiiの$request->getPost())は実際に空であったことに気づきました。 this answerをstackoverflowで読むと、Angular JSとそのデフォルト動作がapllication/json(まあまあまあまあ問題ではないかもしれません)として投稿されるという問題が実際にあるようです。この質問への顕著な答えによって提案され、リンクされた解答の提案に基づいて、私は次のようにYiiのからCHttpRequestクラスをオーバーライドしてしまった:

class AppRequest extends CHttpRequest 
{ 
    public function validateCsrfToken($event) 
    { 
     if ($this->getIsPostRequest() || 
      $this->getIsPutRequest() || 
      $this->getIsPatchRequest() || 
      $this->getIsDeleteRequest() 
     ) { 
      $cookies = $this->getCookies(); 

      $method = $this->getRequestType(); 
      switch ($method) { 
       case 'POST': 
        if (empty($this->getPost($this->csrfTokenName))) { 
         $input = json_decode(file_get_contents('php://input'), true);; 
         $userToken = $input[$this->csrfTokenName]; 
        } else { 
         $userToken = $this->getPost($this->csrfTokenName); 
        } 
        break; 
       case 'PUT': 
        if (empty($this->getPut($this->csrfTokenName))) { 
         $input = json_decode(file_get_contents('php://input'), true);; 
         $userToken = $input[$this->csrfTokenName]; 
        } else { 
         $userToken = $this->getPut($this->csrfTokenName); 
        } 
        break; 
       case 'PATCH': 
        if (empty($this->getPatch($this->csrfTokenName))) { 
         $input = json_decode(file_get_contents('php://input'), true);; 
         $userToken = $input[$this->csrfTokenName]; 
        } else { 
         $userToken = $this->getPatch($this->csrfTokenName); 
        } 
        break; 
       case 'DELETE': 
        if (empty($this->getDelete($this->csrfTokenName))) { 
         $input = json_decode(file_get_contents('php://input'), true);; 
         $userToken = $input[$this->csrfTokenName]; 
        } else { 
         $userToken = $this->getDelete($this->csrfTokenName); 
        } 
        break; 
      } 

      if (!empty($userToken) && $cookies->contains($this->csrfTokenName)) { 
       $cookieToken = $cookies->itemAt($this->csrfTokenName)->value; 
       $valid = $cookieToken === $userToken; 
      } else 
       $valid = false; 
      if (!$valid) 
       throw new CHttpException(400, Yii::t('yii', 'The CSRF token could not be verified.')); 
     } 
    } 
} 
+0

ステータス「400」は、サーバー側で何か問題が発生したことを意味します。必要なパラメーターが本文から正しく渡されない可能性があります。 –

+0

@PankajParkar csrf検証を無効にすると動作します。 – Comforse

+0

あなたはそれを好きなように答えとして追加することができます。 –

答えて

1

あなたはCHttpRequestを見て、検証が行わどのように見ます場合は、あなたは問題を理解するでしょう。

  1. クライアントがクッキーにリクエストを送信し、クッキーを受け入れる資格を得る必要があります。だから我々は2つの条件が必要CSRF検証作業を行うため

    public function validateCsrfToken($event) 
    { 
        if ($this->getIsPostRequest() || 
         $this->getIsPutRequest() || 
         $this->getIsPatchRequest() || 
         $this->getIsDeleteRequest()) 
        { 
         $cookies=$this->getCookies(); 
         $method=$this->getRequestType(); 
         switch($method) 
         { 
          case 'POST': 
           $userToken=$this->getPost($this->csrfTokenName); 
          break; 
          case 'PUT': 
           $userToken=$this->getPut($this->csrfTokenName); 
          break; 
          case 'PATCH': 
           $userToken=$this->getPatch($this->csrfTokenName); 
          break; 
          case 'DELETE': 
           $userToken=$this->getDelete($this->csrfTokenName); 
         } 
         if (!empty($userToken) && $cookies->contains($this->csrfTokenName)) 
         { 
          $cookieToken=$cookies->itemAt($this->csrfTokenName)->value; 
          $valid=$cookieToken===$userToken; 
         } 
         else 
          $valid = false; 
         if (!$valid) 
          throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.')); 
        } 
    } 
    

  2. 私たちのリクエストでトークンを渡す必要があります。

第2の状態は機能しません。 You'rがポストからトークンを取得しようと身体を要求するjsonを渡し、そしてYii

$userToken=$this->getPost($this->csrfTokenName); 

は、この動作を変更するには、例えば、あなたのRequestクラスを使用するCHttpRequestをオーバーライドして、設定ファイルを変更する必要があります

'components' => array(
    'request' => array(
     'class' => 'application.components.HttpRequest', 
     'enableCsrfValidation' => true, 
    ), 
), 

これは、CSRF検証が実行されたときの状況を理解するのに役立ちます。

+0

あなたの答えに感謝します。私は後で見て、それが動作すればあなたの答えをマークします。 – Comforse

+0

ありがとうございます。問題は修正されました。完全な回答で質問を更新しました。 – Comforse

関連する問題