阻止form_token在Drupal“GET”表单中呈现

时间:2009-09-30 10:36:48

标签: drupal drupal-6

Drupal在呈现表单时将form_token作为隐藏字段插入。然后在表单提交上检查form_token以防止跨站点请求伪造攻击。提交的表单数据保证来自Drupal呈现的原始表单。

但是,使用“GET”方法的表单不需要此标记。它所做的只是延长和丑化生成的URL。

有没有办法压制它?

4 个答案:

答案 0 :(得分:13)

是的,有一种方法,但有意识地使用它(见下面的警告):

如果您自己创建表单,请添加

$form['#token'] = FALSE;

到表单定义数组应该防止首先生成令牌。

如果您正在处理现有表单,则可以通过取消设置hook_form_alter上的“#token”元素来绕过令牌验证过程:

// Example for removal of token validation from login (NOTE: BAD IDEA!)
function yourmodule_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'user_login_block') {
    unset($form['#token']);
  }
}

警告:鉴于您的问题,我认为对于GET和POST请求之间的差异(更好,没有差异)存在轻微的误解。

  

...使用“GET”方法在表单上   不应该需要这个令牌。一切都做到了   是延长和丑化结果   URL。

这是错的! GET和POST只是两种不同的,但大多数等效的方法,用于将数据从客户端传输到服务器。由于POST更适合传输大量数据(或难以格式化的数据),因此它是提交表单的既定标准,但它绝不比GET请求更安全/更不安全或更安全/更不安全。恶意用户可以以相同的方式篡改这两种类型的请求,因此两种类型都应使用相同的保护机制

使用GET请求,令牌与POST请求完全相同 - 它向服务器证明提交的数据来自与他构建的请求相同的计算机上的相同浏览器表格!因此,只有在您确定不能通过XSRF滥用请求时才应将其删除。

答案 1 :(得分:9)

这对我有用。我不得不取消设置所有形式的api元素并将#token属性设置为false。注意after_build函数用于取消设置其他属性。

   function mymodule_form(&$form_state){
      $form['name'] = array(
        '#type'   => 'textfield',
        '#title'  => 'name',
        '#value'  => 'name', 
      );
      $form['#method'] = 'get';
      $form['#action'] = url('someurl');
      $form['submit'] = array('#type' => 'submit', '#value' => 'go');
      $form['#token'] = false;
      $form['#after_build'] = array('mymodule_unset_default_form_elements');
      return $form;
    }

    function mymodule_unset_default_form_elements($form){
      unset($form['#build_id'], $form['form_build_id'], $form['form_id']);
      return $form;
    }

答案 2 :(得分:4)

我工作的网站使用Drupal 6表单API进行自定义搜索表单,因此通过删除令牌和构建ID,我们可以将结果缓存在memcache中。现在我们已经转移到Acquia托管,它使用Varnish进行缓存。

要从表单中删除form_token和form_build_id并将其作为GET请求提交,请使用以下方法:

<?php

function module_example_form($form_state, $form_id = NULL) {
  // Form root settings.
  $form = array();

  // Set the submission callback for this form. 
  $form['#submit'][] = __FUNCTION__ . '_submit';

  // Set the request method for this form to GET instead of the default
  // of POST.
  $form['#method'] = 'get';

  // Remove unique form token so request can be cached. This is accompanied by
  // code in hook_form_alter to ignore the token and remove the build_id.
  $form['#token'] = FALSE;

  // Submit button.
  $form['go'] = array(
    '#type' => 'submit',
    '#value' => t('Go!'),
  );

  return $form;
}

/**
 * Implements hook_form_alter().
 */
function module_form_alter(&$form, $form_state, $form_id) {
  // Changes to the 'module_example_form' form.
  if ($form_id == 'module_example_form') {
    // Unset the hidden token field and form_build_id field.
    unset($form['#token'], $form['form_build_id'], $form['#build_id']);
  }
}

?>

答案 3 :(得分:4)

我发现简单地丢弃CSRF令牌是一个选项。我们使用hook_theme_registry_alter()解决了它,以覆盖Drupal核心theme_hidden()函数,以便隐藏的表单元素“form_token”呈现为<esi />标记。该标记将使Varnish调用我们允许通过缓存的PHP文件。此文件将为当前用户计算正确的表单标记,然后输出隐藏字段的HTML代码。你可以计算这个令牌而不用一个Drupal引导程序,但你 需要一个数据库查询来获取你网站的* drupal_private_key *,它存储在中变量表。