Security issue: can change ?site=foo to ?site=bar and be logged into another site

chriskuhar wrote on Wednesday, October 16, 2013:

I am not sure if this is the right way to fix the issue, but this is an issue.

This pertains to a server with more than one site, and a user is logged into one site, by changing the URL, they have access to another site.

In the browser navigator bar, there is the site URL which contains the site url, for example, this goes for any URL.

http://emr.mysite.com/interface/main/main_screen.php?auth=login&site=foo

Now change the URL to another site

http://emr.mysite.com/interface/main/main_screen.php?auth=login&site=bar

notice you are now viewing data from another site.

It would be nice to have this fixed, below is my fix, but maybe someone with a better understanding of the system has a better one?

The idea is to check the site value in the url, check it against the $_SESSION value, if it is different, clean the session out and send user to login page.

macky{ckuhar}2020: git diff globals.php
diff --git a/interface/globals.php b/interface/globals.php
index 9fa70ec…4270f17 100644
— a/interface/globals.php
+++ b/interface/globals.php
@@ -105,6 +105,14 @@ if (empty($_SESSION[‘site_id’]) || !empty($_GET[‘site’])) {
$tmp = $_SERVER[‘HTTP_HOST’];
if (!is_dir($GLOBALS[‘OE_SITES_BASE’] . “/$tmp”)) $tmp = “default”;
}

  • if (!empty($_SESSION[‘site_id’]) && !empty($tmp) &&
  •   (strcasecmp($_SESSION['site_id'], $tmp) !== 0) &&
    
  •   !empty($_SESSION['userauthorized'])) {
    
  •     session_unset();  // clear session, clean logout
    
  •     header('Location: /interface/login_screen.php'); 
    
  •     exit;
    
  • }
  • if (empty($tmp) || preg_match(’/[^A-Za-z0-9\-.]/’, $tmp))
    die(“Site ID '”. htmlspecialchars($tmp,ENT_NOQUOTES) . “’ contains invalid characters.”);
    if (!isset($_SESSION[‘site_id’]) || $_SESSION[‘site_id’] != $tmp) {

yehster wrote on Wednesday, October 16, 2013:

Another option is to make the session cookie site specific.


by using a different session name for different sites.

The top.restoreSession() javascript function would also need to be updated to use the variable cookie name.

The advantage of this approach would be that one could be logged in to two sites at the same time.

yehster wrote on Wednesday, October 16, 2013:

Also, of note, switching sites by changing the siteID in the query string only gets you into the other site if the same username exists on both sites.

yehster wrote on Wednesday, October 16, 2013:

Chris,
Thinking about it a little more, the site id check you are proposing can coexist with a site-specific session name. Doing both might provide some additional security in case there’s something else that’s been missed as part of the multi-site module.

chriskuhar wrote on Wednesday, October 16, 2013:

You are right Kevin, that is the proper solution, I’ll track that solution down.

user “admin” is a default value, but a security minded person would change that.

yehster wrote on Thursday, October 17, 2013:

It’s not a slam dunk though.

It looks like Brady actually changed away from that paradigm for various reasons a long time ago.

bradymiller wrote on Thursday, October 17, 2013:

Hi,
Very interesting (and real) vulnerability. Chris’s initial strategy seems like enough (ie. if the GET site (note empty is default) is not equal to the SESSION site, then die; I’m not sure if killing the session is needed, though?).
-brady
OpenEMR

bradymiller wrote on Thursday, October 17, 2013:

actually, looking at code in interface/globals.php looks like an empty GET site is not equivalent to default (minor error in my post above).
At the end of the current code there can the conditional to $_SESSION[‘site_id’] != $tmp be used to instead die rather than changing the $_SESSION[‘site_id’] to $tmp .

cmswest wrote on Friday, October 18, 2013:

separate issue:

once you’re setup with admin, you have to go into database and hand edit users tables to change and then would have to fix password or else there’s a login issue?

cmswest wrote on Friday, October 18, 2013:

or create new admin with unique user name and then delete username admin?

bradymiller wrote on Sunday, October 20, 2013:

Hi,

Tested this out some and here’s a hopeful robust fix for this:

Let me know your thoughts Chris, Kevin?

Rod, since you know this multisite module best, see any obvious issues here?

Also will need to ensure it doesn’t break the patient portal along with installation/upgrading of new multisite instances.

-brady
OpenEMR

sunsetsystems wrote on Monday, October 21, 2013:

A couple of comments.

First, it used to be that both username and password were checked (via authCheckSession() in library/auth.inc) on each web access. However when RSA key pairs where introduced on 5/28, it appears this was changed so that only the username is checked, not the password. I’m wondering if this could result in other vulnerabilities? Kevin, can you comment?

So anyway, before this change you had to have the same username and password in both sites in order to get this kind of access. But in that case, you had the access anyway. So it was more of an oddity than a vulnerability. Now it’s a vulnerability.

Brady, your fix seems OK if that’s the only relevant vulnerability, however I think the above-mentioned checkSession() function would be a more appropriate place for it.

Rod
http://www.sunsetsystems.com/

yehster wrote on Tuesday, October 22, 2013:

I think that explicitly checking that the siteID matches is more important than a password check, because it happens “earlier” in the sequence of events, and will also catch an inadvertent site switch if “ignoreAuth” is true e.g. when using the portal.

sunsetsystems wrote on Tuesday, October 22, 2013:

I agree that site ID check is good. What I’m wondering is if password check is also desirable. For example if the admin changes my password while I’m logged in, seems I could just keep merrily using the system as long as I don’t log out. Are there other such vulnerabilities?

Rod
http://www.sunsetsystems.com/

yehster wrote on Tuesday, October 22, 2013:

I agree that adding the password check is a good idea. Just wanted it clear that it needs to be in addition to the site ID check and not instead of.

bradymiller wrote on Wednesday, October 23, 2013:

That specific example does not seem like a vulnerability, though. Just because the admin changes the password does not mean the user should be logged out(or does it??). However, if a admin disables the user, then the user should be logged out; will that happen currently in OpenEMR if a user is inactivated?
-brady
OpenEMR

visolveemr wrote on Wednesday, October 23, 2013:

Brady
If a admin disables the user,then that user is not logging out. This is not happening currently in OpenEMR.

Thanks
OpenEMR Customization/Support provider,
ViSolve Inc
services@visolve.com

yehster wrote on Wednesday, October 23, 2013:


Adding “AND active!=0” to the query here will kick a user out.

sunsetsystems wrote on Wednesday, October 23, 2013:

Probably best if either changing the password or inactivating denies access right away, as that’s surely the intent.

Rod
http://www.sunsetsystems.com/

bradymiller wrote on Thursday, October 24, 2013:

Hi,

So, would place the hash in a session variable then? And ensure this matches, as with the user being active, on each authCheckSession() request? This in addition to the ensure site matches sounds like would be much more secure overall. I contributed the site fix, Kevin contributed the active user fix, I wonders who’s up to contribute the password check/fix… :slight_smile:

-brady