1

This seems to be a massive security floor in Drupal. I have the following display suite code in a Block which is added as a custom field to the User account display:-

    <?php
global $user;
$uid = arg(1);
$user = user_load($uid);
$roles = $user->roles;

if (in_array('RoleName1', array_values($roles))) {
 print "<a href='/xyz'><img src='/sites/default/files/image.png' style='max-height:200px;max-width:200px;'></a>";
}
if (in_array('RoleName2', array_values($roles))) {
 print "<a href='/xyz'><img src='/sites/default/files/image.png' style='max-height:200px;max-width:200px;'></a>";
}

?>

It checks for a couple of Roles and shows an image if they have a particular Role.

When an anonymous user now loads a user account page, they are logged in as that user! Visiting "/user/1" means they are logged in as the admin user!!!

1
  • OK, not a security floor in the Drupal code, but maybe in the Documentation. There could be more prominent warnings when using certain keywords in display suite or custom php blocks.
    – Darren
    Commented Feb 23, 2017 at 20:34

3 Answers 3

3

This is no security hole, it's the custom code you shared.

// When you load the global user object ...
global $user;
// ... and then assign another user object to the global $user object ...
$user = user_load(<any_uid>);
// ... Drupal basically changes the context of the current user.
// It's kind of a hacky login by code.
// Hacky because, till this code executes
// there's no log about the user login, until drupal writes the current session into the database.

Typically $account is advised to prevent accidents like this.

$account = user_load(<any_uid>);
4
  • 1
    Exactly. You are loading the user en force and printing strings. This isn't native Drupal code.
    – Kevin
    Commented Feb 23, 2017 at 20:09
  • OK, so it's not native drupal code but a site builder read a guide on drupal showing how to check for user roles, then copy-pasted this into a display suite block.
    – Darren
    Commented Feb 23, 2017 at 20:32
  • 1
    It's just wrong - global $user designates the current user, and then they're overwriting it with the user id from the URL. This should never be done. A proper way to do this would be $account = menu_get_object('user'); or $account = user_load(arg(1)); - don't assign to $user.
    – Kevin
    Commented Feb 23, 2017 at 20:36
  • 2
    Also, there is no protection against enabling PHP filter and copy pasting PHP code into blocks in Drupal. It is generally not advised to be doing this.
    – Kevin
    Commented Feb 23, 2017 at 20:37
0

So the actual answer is that loading the $user object in a display suite code block, with a different ID than the current session user, means they will assume the identity of that user along with all their permissions.

Then allowing this block to be displayed to anonymous users, e.g. a dynamic block on the public user profile page, means that even users without a valid login could potentially browse to the block in question and gain entry.

BEWARE site builders and copy-pasters!

As @Kevin posted below, the best way to do it is:-

$account = menu_get_object('user'); 

or

$account = user_load(arg(1)); - 

Don't assign anything to the $user object. This shouldn't really be available to the code.

3
  • just a small clarity, there is nothing wrong with $user, but issue comes after global $user; now onwards $user is pointing to global user object which is current user.
    – arpitr
    Commented Feb 23, 2017 at 20:51
  • 2
    Typically $account is advised to prevent accidents like this
    – Kevin
    Commented Feb 23, 2017 at 20:59
  • that's true!, just wanted to highlight global scope which I think Darren forgot to mention in the answer, thanks @Kevin :)
    – arpitr
    Commented Feb 23, 2017 at 21:33
0

Be sure to read Safely Impersonating Another User, which describes how to do so securely for Drupal 6, 7, or 8. The code in the question is not secure.

If you do need to actually switch to a different user during a page request, then the following code will do so:

global $user; 
$original_user = $user; 
$old_state = session_save_session(); 
session_save_session(FALSE); 
$user = user_load(array('uid' => 1)); 
// Take your action here where you pretend to be the user with UID = 1 (typically the admin user on a site) 
// If your code fails, it's not a problem because the session will not be saved 
$user = $original_user; 
session_save_session($old_state); 
// From here on the $user is back to normal so it's OK for the session to be saved 

If however, switching the global user is not what you had intended then the answers by arpitr and Darren should be used.

Note that if the page is cached, then internal data can be leaked.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.