Michele Wickham

The mostly coherent ramblings of a web developer.

Overriding Password Request Validation in Drupal 6

Mon, 01/23/2012 - 20:03 -- Michele

I enjoy security audits. Mostly. At least at this point in my career as a web developer I know what to expect and have tackled the obvious things like XSS and SQL injection. Sanitize, fools!

Of course, I got there with no small amount of education and embarrassment.

So the latest thing I needed to do was prevent Drupal 6 from revealing whether or not a requested password was valid. Sounds counter-intuitive, but the idea is to prevent hackers from discovering that they have found a valid user name in the system so that they can't brute force their way in. The Login Security module is very helpful for preventing the most common brute force attacks on user login, but there's nothing helpful for the password request page. What to do?

Touching core is out of the question because of its alleged kitten killing capabilities. And there shouldn't be a reason to hack core when there are so many handy hooks built into the Drupal API for virtually any purpose.

The solution for me was to add a form alter for the password request page. It looked something like this:

function mymodule_form_user_pass_alter(&$form, &$form_state) {
    $form['#validate'] = array('mymodule_pass_validate');
}

Note that instead of adding to the array of validators, I simply made it take only my validator. Then, I basically copied the entire validation function directly from the user module and made a small modification to the fail statement like so:

function mymodule_pass_validate($form, &$form_state) {
    $name = trim($form_state['values']['name']);
    // Try to load by email.
    $account = user_load(array('mail' => $name, 'status' => 1));
    if (!$account) {
        // No success, try to load by name.
        $account = user_load(array('name' => $name, 'status' => 1));
    }
    if ($account) {
        // Blocked accounts cannot request a new password,
        // check provided username and email against access rules.
        if (drupal_is_denied('user', $account->name) || drupal_is_denied('mail', $account->mail)) {
            form_set_error('name', t('%name is not allowed to request a new password.', array('%name' => $name)));
        }
    }
    if (isset($account->uid)) {
        form_set_value(array('#parents' => array('account')), $account, $form_state);
    } else {
// What the validation did by default
//    form_set_error('name', t('Sorry, %name is not recognized as a user name or an e-mail address.', array('%name' => $name)));
// Updated version - redirected this way to copy behavior and slowdown brute force behavior
        drupal_set_message(t('Your password and further instructions have been sent to your e-mail address.'));
        drupal_goto('/user');
        exit();
    }
}

Now when a user requests a password, it looks exactly as if the request was for a valid user, even if it wasn't.

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.