Disable autocomplete on CSRF/Security token fields.

New versions of Safari will overwrite these fields when a user uses the
back button. If one-time CSRF tokens are in use the request will be
blackholed.

Refs #10486
This commit is contained in:
mark_story 2017-04-05 13:02:17 -04:00
parent 01abf29bed
commit 5685c031e2
2 changed files with 66 additions and 34 deletions

View file

@ -592,7 +592,7 @@ class FormHelperTest extends CakeTestCase {
'div' => array('style' => 'display:none;'),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testKey', 'id'
'type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testKey', 'id', 'autocomplete'
)),
'/div'
);
@ -708,11 +708,13 @@ class FormHelperTest extends CakeTestCase {
'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/',
'form' => 'MyTestForm',
'autocomplete' => 'off',
)),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/',
'form' => 'MyTestForm',
'autocomplete' => 'off',
)),
'/div'
);
@ -877,11 +879,13 @@ class FormHelperTest extends CakeTestCase {
'div' => array('style' => 'display:none;'),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/'
'value' => $hash, 'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/'
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)),
'/div'
);
@ -924,11 +928,13 @@ class FormHelperTest extends CakeTestCase {
'div' => array('style' => 'display:none;'),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => 'preg:/.+/', 'id' => 'preg:/TokenFields\d+/'
'value' => 'preg:/.+/', 'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => 'cancel%7Csave', 'id' => 'preg:/TokenUnlocked\d+/'
'value' => 'cancel%7Csave', 'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)),
'/div'
);
@ -1044,11 +1050,13 @@ class FormHelperTest extends CakeTestCase {
'div' => array('style' => 'display:none;'),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/'
'value' => $hash, 'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/'
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)),
'/div'
);
@ -1108,12 +1116,18 @@ class FormHelperTest extends CakeTestCase {
$expected = array(
'div' => array('style' => 'display:none;'),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/'
'type' => 'hidden', 'name' =>
'data[_Token][fields]',
'value' => $hash,
'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off'
)),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => 'address%7Cfirst_name', 'id' => 'preg:/TokenUnlocked\d+/'
'type' => 'hidden',
'name' => 'data[_Token][unlocked]',
'value' => 'address%7Cfirst_name',
'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off'
)),
'/div'
);
@ -1157,12 +1171,18 @@ class FormHelperTest extends CakeTestCase {
$expected = array(
'div' => array('style' => 'display:none;'),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/'
'type' => 'hidden',
'name' => 'data[_Token][fields]',
'value' => $hash,
'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => 'address%7Cfirst_name', 'id' => 'preg:/TokenUnlocked\d+/'
'type' => 'hidden',
'name' => 'data[_Token][unlocked]',
'value' => 'address%7Cfirst_name',
'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)),
'/div'
);
@ -1201,8 +1221,11 @@ class FormHelperTest extends CakeTestCase {
'div' => array('style' => 'display:none;'),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][key]',
'value' => 'testKey', 'id' => 'preg:/Token\d+/'
'type' => 'hidden',
'name' => 'data[_Token][key]',
'value' => 'testKey',
'id' => 'preg:/Token\d+/',
'autocomplete' => 'off',
)),
'/div'
);
@ -1282,12 +1305,18 @@ class FormHelperTest extends CakeTestCase {
$expected = array(
'div' => array('style' => 'display:none;'),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/'
'type' => 'hidden',
'name' => 'data[_Token][fields]',
'value' => $hash,
'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)),
array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/'
'type' => 'hidden',
'name' => 'data[_Token][unlocked]',
'value' => '',
'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)),
'/div'
);
@ -8143,14 +8172,14 @@ class FormHelperTest extends CakeTestCase {
),
array('div' => array('style' => 'display:none;')),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/', 'autocomplete')),
'/div',
'button' => array('type' => 'submit'),
'Delete',
'/button',
array('div' => array('style' => 'display:none;')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/', 'autocomplete')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'autocomplete')),
'/div',
'/form',
);
@ -8271,10 +8300,10 @@ class FormHelperTest extends CakeTestCase {
'name', 'id', 'style' => 'display:none;'
),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'test', 'id')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'test', 'id', 'autocomplete')),
'div' => array('style' => 'display:none;'),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => $hash, 'id')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => $hash, 'id', 'autocomplete')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id', 'autocomplete')),
'/div',
'/form',
'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'),
@ -8353,10 +8382,10 @@ class FormHelperTest extends CakeTestCase {
'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;'
),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/', 'autocomplete' => 'off')),
'div' => array('style' => 'display:none;'),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/', 'autocomplete')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'autocomplete')),
'/div',
'/form',
'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'),
@ -8380,10 +8409,10 @@ class FormHelperTest extends CakeTestCase {
'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;'
),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testkey', 'id' => 'preg:/Token\d+/', 'autocomplete' => 'off')),
'div' => array('style' => 'display:none;'),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/', 'autocomplete')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'autocomplete')),
'/div',
'/form',
'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'),

View file

@ -504,7 +504,8 @@ class FormHelper extends AppHelper {
}
return $this->hidden('_Token.key', array(
'value' => $this->request->params['_Token']['key'], 'id' => 'Token' . mt_rand(),
'secure' => static::SECURE_SKIP
'secure' => static::SECURE_SKIP,
'autocomplete' => 'off',
));
}
@ -614,12 +615,14 @@ class FormHelper extends AppHelper {
'value' => urlencode($fields . ':' . $locked),
'id' => 'TokenFields' . mt_rand(),
'secure' => static::SECURE_SKIP,
'autocomplete' => 'off',
));
$out = $this->hidden('_Token.fields', $tokenFields);
$tokenUnlocked = array_merge($secureAttributes, array(
'value' => urlencode($unlocked),
'id' => 'TokenUnlocked' . mt_rand(),
'secure' => static::SECURE_SKIP,
'autocomplete' => 'off',
));
$out .= $this->hidden('_Token.unlocked', $tokenUnlocked);
return $this->Html->useTag('hiddenblock', $out);