Prevent storing formdata to cookies.

- XSS an be stored in a cookie and potentially abused in other ways, so
to prevent this we need to use session instead. This requires the user
to have a session with silverstripe, but this is better than saving
potentially malicious content in cookies. (Also some cookies have
limited length).

@see https://github.com/silverstripe/silverstripe-comments/issues/263
This commit is contained in:
Simon Gow 2018-09-20 14:53:35 +12:00
parent cf86b2bb21
commit 747d4f4402
1 changed files with 33 additions and 17 deletions

View File

@ -14,7 +14,6 @@ use SilverStripe\Forms\RequiredFields;
use SilverStripe\Forms\TextareaField; use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\TextField; use SilverStripe\Forms\TextField;
use SilverStripe\Security\Member; use SilverStripe\Security\Member;
use SilverStripe\Control\Cookie;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Security\Security; use SilverStripe\Security\Security;
use SilverStripe\Comments\Model\Comment; use SilverStripe\Comments\Model\Comment;
@ -132,21 +131,28 @@ class CommentForm extends Form
// Set it so the user gets redirected back down to the form upon form fail // Set it so the user gets redirected back down to the form upon form fail
$this->setRedirectToFormOnValidationError(true); $this->setRedirectToFormOnValidationError(true);
// load any data from the cookies // load any data from the session
if ($data = Cookie::get('CommentsForm_UserData')) { $data = $this->getSessionData();
$data = Convert::json2array($data); if (is_array($data)) {
$this->loadDataFrom(array( // load user data from previous form request back into form.
'Name' => isset($data['Name']) ? $data['Name'] : '', if (array_key_exists('UserData', $data)) {
'URL' => isset($data['URL']) ? $data['URL'] : '', $formData = Convert::json2array($data['UserData']);
'Email' => isset($data['Email']) ? $data['Email'] : ''
));
// allow previous value to fill if comment not stored in cookie (i.e. validation error) $this->loadDataFrom(array(
$prevComment = Cookie::get('CommentsForm_Comment'); 'Name' => isset($formData['Name']) ? $formData['Name'] : '',
'URL' => isset($formData['URL']) ? $formData['URL'] : '',
'Email' => isset($formData['Email']) ? $formData['Email'] : ''
));
}
if ($prevComment && $prevComment != '') { // allow previous value to fill if comment
$this->loadDataFrom(array('Comment' => $prevComment)); if (array_key_exists('Comment', $data)) {
$prevComment = $data['Comment'];
if ($prevComment && $prevComment != '') {
$this->loadDataFrom(array('Comment' => $prevComment));
}
} }
} }
} }
@ -184,8 +190,10 @@ class CommentForm extends Form
} }
// cache users data // cache users data
Cookie::set('CommentsForm_UserData', Convert::raw2json($data)); $form->setSessionData(array(
Cookie::set('CommentsForm_Comment', $data['Comment']); 'UserData' => Convert::raw2json($data),
'Comment' => $data['Comment']
));
// extend hook to allow extensions. Also see onAfterPostComment // extend hook to allow extensions. Also see onAfterPostComment
$this->controller->extend('onBeforePostComment', $form); $this->controller->extend('onBeforePostComment', $form);
@ -246,8 +254,16 @@ class CommentForm extends Form
$this->getRequest()->getSession()->set('CommentsModerated', 1); $this->getRequest()->getSession()->set('CommentsModerated', 1);
} }
// clear the users comment since it passed validation // clear the users comment since the comment was successful.
Cookie::set('CommentsForm_Comment', false); if($comment->exists()){
// Remove the comment data as it's been saved already.
unset($data['Comment']);
}
// cache users data (name, email, etc to prepopulate on other forms).
$form->setSessionData(array(
'UserData' => Convert::raw2json($data),
));
// Find parent link // Find parent link
if (!empty($data['ReturnURL'])) { if (!empty($data['ReturnURL'])) {