2
votes

I am having a problem getting the Security component to validate a posted form and it keeps blackholing the action. Looking into the code I've found that the hashed tokens are not matching.

In the posted form there is only one field that is getting validated (in Security::_validatePost) as being locked. But I'm having problems finding where the Form->create tokens are generated and how.

What are the typical causes for the tokens not matching and where should I check how cake is generating the token both ['_Token']['fields'] and ? (using cake 2.3.7). The form is using ajax validation as well.

Edit: When I dump out the $token value from Security::generateToken it looks like

Array ( [key] => ddc88faacf41985f41359ff99d9c6f87549611c7 [allowedControllers] => Array ( )

[allowedActions] => Array
    (
    )

[unlockedFields] => Array
    (
    )

[csrfTokens] => Array
    (
        [f8c40609a0a86db23bfa5ea2d258723d3caff55a] => 1375207459
        [084c3363363591c3024c59452899a2f4f60ecf99] => 1375207655
        [0344c686c549927c1e27729ae95d879a4034bdab] => 1375207678
        [dfb940ec034e82b10f7b3cc5677734da6896dfbc] => 1375207762
        [ddc88faacf41985f41359ff99d9c6f87549611c7] => 1375207791
    )

However for the created form the token in Security::_validatePost when the form is posted is

token=6521bb362f8323e8f871814fc5d37a79c93e294e check=e8c40d174a23e8797d906d6e381a9a0acc1425ed

Where token is taken from

$check = $controller->request->data;
$token = urldecode($check['_Token']['fields']);

and check is later redefined as:

$check = Security::hash(serialize($fieldList) . $unlocked . Configure::read('Security.salt'), 'sha1');

then $token and $check are compared and false which leads to the blackhole.

2

2 Answers

4
votes

I found that one field was not being added to the POSTED form field's list because it was an unchecked CHECKBOX (see edit below). I thought I would outline a general debugging procedure to help people with Security Form Validation issues.

In order to see the mechanisms I dug into the code to see how the FormHelper hash is created vs. how the SecurityComponent validation checks the hash. Here's how to see exactly what is happening behind the scenes.

Checking the input to the FormHelper. Open CORE/Cake/View/Helper/FormHelper.php. In the secure() function add some pr lines around the $files=Security::hash line to see how the tokens are built:

pr($fields);//hashed into computed token on next line
$fields = Security::hash(serialize($fields) . $unlocked . Configure::read('Security.salt'), 'sha1');
pr($unlocked); //hashed into computed token
pr(Configure::read('Security.salt')); //hashed into computed token
pr($fields); //computed token passed via hidden token field in form

Check how form is processed Now check how the submitted form is processed and compared to the passed token: Open the CORE/Cake/Controller/Component/SecurityComponent.php. Insert some pr lines in the _validatePost() routine at the end:

pr($fieldList); //hashed into computed token
pr($unlocked); //hashed into computed token
pr(Configure::read('Security.salt')); //hashed into computed token
pr($token); //passed token from FormHelper
pr($check); //computed token

Hopefully this helps someone else who has problems with locked/unlocked or missing fields quickly figure out what is going on inside of your cake.

EDIT: The field that was causing the problem was a CHECKBOX. When it is not selected by the user the field is not submitted by the POST action. The missing field causes the SecurityComponent to fail vaildation. To avoid this on check boxes add this to the form:

$this->Form->unlockField('checkbox.field.name');
1
votes

Do you have fields created or deleted by Javascript in the view? There you go. See also the book for the security component.

You have to white list these fields if you want to use them.