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;'), 'div' => array('style' => 'display:none;'),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testKey', 'id' 'type' => 'hidden', 'name' => 'data[_Token][key]', 'value' => 'testKey', 'id', 'autocomplete'
)), )),
'/div' '/div'
); );
@ -708,11 +708,13 @@ class FormHelperTest extends CakeTestCase {
'type' => 'hidden', 'name' => 'data[_Token][fields]', 'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/', 'value' => $hash, 'id' => 'preg:/TokenFields\d+/',
'form' => 'MyTestForm', 'form' => 'MyTestForm',
'autocomplete' => 'off',
)), )),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/',
'form' => 'MyTestForm', 'form' => 'MyTestForm',
'autocomplete' => 'off',
)), )),
'/div' '/div'
); );
@ -877,11 +879,13 @@ class FormHelperTest extends CakeTestCase {
'div' => array('style' => 'display:none;'), 'div' => array('style' => 'display:none;'),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]', 'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/' 'value' => $hash, 'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)), )),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/' 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)), )),
'/div' '/div'
); );
@ -924,11 +928,13 @@ class FormHelperTest extends CakeTestCase {
'div' => array('style' => 'display:none;'), 'div' => array('style' => 'display:none;'),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]', 'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => 'preg:/.+/', 'id' => 'preg:/TokenFields\d+/' 'value' => 'preg:/.+/', 'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)), )),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => 'cancel%7Csave', 'id' => 'preg:/TokenUnlocked\d+/' 'value' => 'cancel%7Csave', 'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)), )),
'/div' '/div'
); );
@ -1044,11 +1050,13 @@ class FormHelperTest extends CakeTestCase {
'div' => array('style' => 'display:none;'), 'div' => array('style' => 'display:none;'),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]', 'type' => 'hidden', 'name' => 'data[_Token][fields]',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/' 'value' => $hash, 'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)), )),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'type' => 'hidden', 'name' => 'data[_Token][unlocked]',
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/' 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)), )),
'/div' '/div'
); );
@ -1108,12 +1116,18 @@ class FormHelperTest extends CakeTestCase {
$expected = array( $expected = array(
'div' => array('style' => 'display:none;'), 'div' => array('style' => 'display:none;'),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]', 'type' => 'hidden', 'name' =>
'value' => $hash, 'id' => 'preg:/TokenFields\d+/' 'data[_Token][fields]',
'value' => $hash,
'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off'
)), )),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'type' => 'hidden',
'value' => 'address%7Cfirst_name', 'id' => 'preg:/TokenUnlocked\d+/' 'name' => 'data[_Token][unlocked]',
'value' => 'address%7Cfirst_name',
'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off'
)), )),
'/div' '/div'
); );
@ -1157,12 +1171,18 @@ class FormHelperTest extends CakeTestCase {
$expected = array( $expected = array(
'div' => array('style' => 'display:none;'), 'div' => array('style' => 'display:none;'),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]', 'type' => 'hidden',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/' 'name' => 'data[_Token][fields]',
'value' => $hash,
'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)), )),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'type' => 'hidden',
'value' => 'address%7Cfirst_name', 'id' => 'preg:/TokenUnlocked\d+/' 'name' => 'data[_Token][unlocked]',
'value' => 'address%7Cfirst_name',
'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)), )),
'/div' '/div'
); );
@ -1201,8 +1221,11 @@ class FormHelperTest extends CakeTestCase {
'div' => array('style' => 'display:none;'), 'div' => array('style' => 'display:none;'),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][key]', 'type' => 'hidden',
'value' => 'testKey', 'id' => 'preg:/Token\d+/' 'name' => 'data[_Token][key]',
'value' => 'testKey',
'id' => 'preg:/Token\d+/',
'autocomplete' => 'off',
)), )),
'/div' '/div'
); );
@ -1282,12 +1305,18 @@ class FormHelperTest extends CakeTestCase {
$expected = array( $expected = array(
'div' => array('style' => 'display:none;'), 'div' => array('style' => 'display:none;'),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][fields]', 'type' => 'hidden',
'value' => $hash, 'id' => 'preg:/TokenFields\d+/' 'name' => 'data[_Token][fields]',
'value' => $hash,
'id' => 'preg:/TokenFields\d+/',
'autocomplete' => 'off',
)), )),
array('input' => array( array('input' => array(
'type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'type' => 'hidden',
'value' => '', 'id' => 'preg:/TokenUnlocked\d+/' 'name' => 'data[_Token][unlocked]',
'value' => '',
'id' => 'preg:/TokenUnlocked\d+/',
'autocomplete' => 'off',
)), )),
'/div' '/div'
); );
@ -8143,14 +8172,14 @@ class FormHelperTest extends CakeTestCase {
), ),
array('div' => array('style' => 'display:none;')), array('div' => array('style' => 'display:none;')),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), 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', '/div',
'button' => array('type' => 'submit'), 'button' => array('type' => 'submit'),
'Delete', 'Delete',
'/button', '/button',
array('div' => array('style' => 'display:none;')), 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][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/', 'autocomplete')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')), array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'autocomplete')),
'/div', '/div',
'/form', '/form',
); );
@ -8271,10 +8300,10 @@ class FormHelperTest extends CakeTestCase {
'name', 'id', 'style' => 'display:none;' 'name', 'id', 'style' => 'display:none;'
), ),
array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), 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;'), '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][fields]', 'value' => $hash, 'id', 'autocomplete')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id')), array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id', 'autocomplete')),
'/div', '/div',
'/form', '/form',
'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'), '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;' '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' => '_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;'), '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][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/', 'autocomplete')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')), array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'autocomplete')),
'/div', '/div',
'/form', '/form',
'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'), '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;' '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' => '_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;'), '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][fields]', 'value' => 'preg:/[\w\d%]+/', 'id' => 'preg:/TokenFields\d+/', 'autocomplete')),
array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/')), array('input' => array('type' => 'hidden', 'name' => 'data[_Token][unlocked]', 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/', 'autocomplete')),
'/div', '/div',
'/form', '/form',
'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'), '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( return $this->hidden('_Token.key', array(
'value' => $this->request->params['_Token']['key'], 'id' => 'Token' . mt_rand(), '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), 'value' => urlencode($fields . ':' . $locked),
'id' => 'TokenFields' . mt_rand(), 'id' => 'TokenFields' . mt_rand(),
'secure' => static::SECURE_SKIP, 'secure' => static::SECURE_SKIP,
'autocomplete' => 'off',
)); ));
$out = $this->hidden('_Token.fields', $tokenFields); $out = $this->hidden('_Token.fields', $tokenFields);
$tokenUnlocked = array_merge($secureAttributes, array( $tokenUnlocked = array_merge($secureAttributes, array(
'value' => urlencode($unlocked), 'value' => urlencode($unlocked),
'id' => 'TokenUnlocked' . mt_rand(), 'id' => 'TokenUnlocked' . mt_rand(),
'secure' => static::SECURE_SKIP, 'secure' => static::SECURE_SKIP,
'autocomplete' => 'off',
)); ));
$out .= $this->hidden('_Token.unlocked', $tokenUnlocked); $out .= $this->hidden('_Token.unlocked', $tokenUnlocked);
return $this->Html->useTag('hiddenblock', $out); return $this->Html->useTag('hiddenblock', $out);