Commit 4f17920c authored by webchick's avatar webchick
Browse files

#319466: SA-2008-47 (#295053): CSRF in cached forms.

parent 819b0e95
...@@ -100,7 +100,7 @@ function drupal_get_form($form_id) { ...@@ -100,7 +100,7 @@ function drupal_get_form($form_id) {
array_unshift($args_temp, $form_id); array_unshift($args_temp, $form_id);
$form = call_user_func_array('drupal_retrieve_form', $args_temp); $form = call_user_func_array('drupal_retrieve_form', $args_temp);
$form_build_id = 'form-' . md5(mt_rand()); $form_build_id = 'form-' . md5(uniqid(mt_rand(), TRUE));
$form['#build_id'] = $form_build_id; $form['#build_id'] = $form_build_id;
drupal_prepare_form($form_id, $form, $form_state); drupal_prepare_form($form_id, $form, $form_state);
// Store a copy of the unprocessed form for caching and indicate that it // Store a copy of the unprocessed form for caching and indicate that it
...@@ -221,10 +221,13 @@ function drupal_rebuild_form($form_id, &$form_state, $args, $form_build_id = NUL ...@@ -221,10 +221,13 @@ function drupal_rebuild_form($form_id, &$form_state, $args, $form_build_id = NUL
function form_get_cache($form_build_id, &$form_state) { function form_get_cache($form_build_id, &$form_state) {
if ($cached = cache_get('form_' . $form_build_id, 'cache_form')) { if ($cached = cache_get('form_' . $form_build_id, 'cache_form')) {
$form = $cached->data; $form = $cached->data;
if ($cached = cache_get('storage_' . $form_build_id, 'cache_form')) { global $user;
$form_state['storage'] = $cached->data; if ((isset($form['#cache_token']) && drupal_valid_token($form['#cache_token'])) || (!isset($form['#cache_token']) && !$user->uid)) {
if ($cached = cache_get('storage_' . $form_build_id, 'cache_form')) {
$form_state['storage'] = $cached->data;
}
return $form;
} }
return $form;
} }
} }
...@@ -234,7 +237,10 @@ function form_get_cache($form_build_id, &$form_state) { ...@@ -234,7 +237,10 @@ function form_get_cache($form_build_id, &$form_state) {
function form_set_cache($form_build_id, $form, $form_state) { function form_set_cache($form_build_id, $form, $form_state) {
// 6 hours cache life time for forms should be plenty. // 6 hours cache life time for forms should be plenty.
$expire = 21600; $expire = 21600;
global $user;
if ($user->uid) {
$form['#cache_token'] = drupal_get_token();
}
cache_set('form_' . $form_build_id, $form, 'cache_form', REQUEST_TIME + $expire); cache_set('form_' . $form_build_id, $form, 'cache_form', REQUEST_TIME + $expire);
if (!empty($form_state['storage'])) { if (!empty($form_state['storage'])) {
cache_set('storage_' . $form_build_id, $form_state['storage'], 'cache_form', REQUEST_TIME + $expire); cache_set('storage_' . $form_build_id, $form_state['storage'], 'cache_form', REQUEST_TIME + $expire);
......
...@@ -232,19 +232,16 @@ function book_remove_form_submit($form, &$form_state) { ...@@ -232,19 +232,16 @@ function book_remove_form_submit($form, &$form_state) {
* Prints the replacement HTML in JSON format. * Prints the replacement HTML in JSON format.
*/ */
function book_form_update() { function book_form_update() {
$cid = 'form_' . $_POST['form_build_id']; $cached_form_state = array();
$bid = $_POST['book']['bid']; $bid = $_POST['book']['bid'];
$cache = cache_get($cid, 'cache_form'); if ($form = form_get_cache($_POST['form_build_id'], $cached_form_state)) {
if ($cache) {
$form = $cache->data;
// Validate the bid. // Validate the bid.
if (isset($form['book']['bid']['#options'][$bid])) { if (isset($form['book']['bid']['#options'][$bid])) {
$book_link = $form['#node']->book; $book_link = $form['#node']->book;
$book_link['bid'] = $bid; $book_link['bid'] = $bid;
// Get the new options and update the cache. // Get the new options and update the cache.
$form['book']['plid'] = _book_parent_select($book_link); $form['book']['plid'] = _book_parent_select($book_link);
cache_set($cid, $form, 'cache_form', $cache->expire); form_set_cache($_POST['form_build_id'], $form, $cached_form_state);
// Build and render the new select element, then return it in JSON format. // Build and render the new select element, then return it in JSON format.
$form_state = array(); $form_state = array();
$form['#post'] = array(); $form['#post'] = array();
......
...@@ -366,7 +366,9 @@ function poll_choice_js() { ...@@ -366,7 +366,9 @@ function poll_choice_js() {
// not process it. We retreive the cached form, add the element, and resave. // not process it. We retreive the cached form, add the element, and resave.
$form_build_id = $_POST['form_build_id']; $form_build_id = $_POST['form_build_id'];
$form_state = array('submitted' => FALSE); $form_state = array('submitted' => FALSE);
$form = form_get_cache($form_build_id, $form_state); if (!$form = form_get_cache($form_build_id, $form_state)) {
exit();
}
$delta = count($_POST['choice']); $delta = count($_POST['choice']);
$key = isset($form['#node']->choice) ? 'new:'. ($delta - count($form['#node']->choice)) : 'new:'. $delta; $key = isset($form['#node']->choice) ? 'new:'. ($delta - count($form['#node']->choice)) : 'new:'. $delta;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment