File uploading (flash) and CSRF validation

I’m trying to upload a file using YUI Uploader (javascript + flash) and everthing seems to work fine until I enable CSRF prevention (‘enableCsrfValidation’=>true).

From my uploader script using POST request I send current user session ID and CSRF token like this:




    $postData = array(

        'sessId'=>Yii::app()->session->getSessionId(),

        'csrfToken'=>Yii::app()->request->getCsrfToken(),

    );



and in my index.php (entry script) I handle POST data and create cookies:




    if(isset($_POST['sessId'], $_POST['csrfToken'])) {

        $_COOKIE['PHPSESSID'] = $_POST['sessId'];

        $_COOKIE['YII_CSRF_TOKEN'] = $_POST['csrfToken'];

    }



When trying to upload a file I get Error 400 (The CSRF token could not be verified). If I disable CSRF validation, then everything works fine. I’ve seen some similar issues and suggestions on this forum, but none of them solved my problem.

Any help with this is greatly appreciated.

thank you!

Is the CSRF token the same on both requests? Try to debug it.

But judging from code in entry script, normally it should work I guess.

Just checked it twice, they are the same…

Ok, I’ve made some more research on validateCsrfToken function of CHttpRequest class (/yii-1.1.3/framework/web/CHttpRequeset.php). Here is the function:




	public function validateCsrfToken($event)

	{

		if($this->getIsPostRequest())

		{

			// only validate POST requests

			$cookies=$this->getCookies();

			if($cookies->contains($this->csrfTokenName) && isset($_POST[$this->csrfTokenName]))

			{

				$tokenFromCookie=$cookies->itemAt($this->csrfTokenName)->value;

				$tokenFromPost=$_POST[$this->csrfTokenName];

				$valid=$tokenFromCookie===$tokenFromPost;

			}

			else

				$valid=false;

			if(!$valid)

				throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.'));

		}

	}



When I try to upload a file print_r($this->getCookies()) in the function itself returns nothing:




CCookieCollection Object

(

[_request:CCookieCollection:private] => CHttpRequest Object

(

[enableCookieValidation] => 1

[enableCsrfValidation] => 1

[csrfTokenName] => YII_CSRF_TOKEN

[csrfCookie] => Array

(

[domain] => .website.com

)


[_requestUri:CHttpRequest:private] => 

[_pathInfo:CHttpRequest:private] => 

[_scriptFile:CHttpRequest:private] => 

[_scriptUrl:CHttpRequest:private] => 

[_hostInfo:CHttpRequest:private] => 

[_url:CHttpRequest:private] => 

[_baseUrl:CHttpRequest:private] => 

[_cookies:CHttpRequest:private] => CCookieCollection Object

*RECURSION*

[_preferredLanguage:CHttpRequest:private] => 

[_csrfToken:CHttpRequest:private] => 

[_port:CHttpRequest:private] => 

[_securePort:CHttpRequest:private] => 

[behaviors] => Array

(

)


[_initialized:CApplicationComponent:private] => 1

[_e:CComponent:private] => 

[_m:CComponent:private] => 

)


[_initialized:CCookieCollection:private] => 1

[_d:CMap:private] => Array

(

)


[_r:CMap:private] => 

[_e:CComponent:private] => 

[_m:CComponent:private] => 

)



even though in index.php print_r($_COOKIE) gives me:




Array

(

[PHPSESSID] => qipnaoc8k33rqk0nm8m6bkfna6

[YII_CSRF_TOKEN] => 7abe57b681464024aa4e6897882fd5c0029bffc9

)



Weird…

You also have to supply the crsf-token via $_POST (just noticed from the code-snipped you posted).

Not sure about the cookie issue yet.

Thanks, Y!! =)

Here is what I have now in my upload script:




    $postData = array(

        'YII_CSRF_TOKEN'=>Yii::app()->request->getCsrfToken(),

        'PHPSESSID'=>Yii::app()->session->getSessionId(),

        'TOKEN_FOR_COOKIE'=>$_COOKIE['YII_CSRF_TOKEN']

    );



and in my entry script (index.php):




    if(isset($_POST['PHPSESSID'], $_POST['YII_CSRF_TOKEN'], $_POST['TOKEN_FOR_COOKIE'])) {

        $_COOKIE['PHPSESSID'] = $_POST['PHPSESSID'];

        $_COOKIE['YII_CSRF_TOKEN'] = $_POST['TOKEN_FOR_COOKIE'];

    }



I just had to:

  1. Send to $_POST[‘YII_CSRF_TOKEN’] a token generated by Yii::app()->request->getCsrfToken();

  2. In the entry script populate empty cookie with $_COOKIE[‘YII_CSRF_TOKEN’] of the currently logged in user.

Note that Yii::app()->request->getCsrfToken() and $_COOKIE[‘YII_CSRF_TOKEN’] are different things which confused me at the very beginning.