I'm writing a multi-tenant application where accounts are scoped by subdomains. This adds considerable complexity and I'm starting to worry about security.

Each user can have several accounts. For example, assuming acme.com is my app, elmer.acme.com and fudd.acme.com can belong to the same user. When logged in, users can add new accounts, and/or switch contexts to a different account if they already own another one.

When users register, I create a remember_token attribute (different than the password) that gets stored. It value is a random base 64 string. I then create an .acme.com cookie with that value. This ensures that users are logged in under every context.

When viewing elmer.acme.com

When switching to fudd.acme.com or any other acme.com domain or subdomain.

When adding a new account bugs.acme.com

I noticed that other multi-tenant apps scope their session cookies on subdomain basis. So, on UserVoice, logging into elmer.uservoice.com and going to fudd.uservoice.com requires you log in again.

Without knowing the answer myself, how "difficult" is it to generate the universe of base64 and spin up X sessions for it as a bot wanting admin?
–
Woot4MooJun 6 '12 at 19:34

Just an aside: have you thought about whether you have appropriate info to guard against CSRF?
–
Jeff Ferland♦Jun 6 '12 at 19:35

@JeffFerland, Yes. I have that covered. Rails has a handy controller method called protect_from_forgery which inserts a random token.
–
MohamadJun 6 '12 at 20:08

@Woot4Moo, I can't say I know the answer to that myself. Presumably difficult enough to deter would be attackers. My login system is borrowed from an authoritative reference that has been implemented and tested a plethora of times; and I followed to devotedly, until the issue of subdomains cropped up.
–
MohamadJun 6 '12 at 20:10

2 Answers
2

You asked: Am I exposing potential vulnerabilities by exposing the same session cookie to all my users' subdomains?

Answer:It depends, but generally speaking, yes, you could be exposing yourself to some attacks. It depends upon what kind of content you allow on the subdomains (e.g., elmer.acme.com). There are two cases:

If you allow Elmer to put arbitrary HTML on the website hosted at his subdomain elmer.acme.com, then you have a problem. Using the same session cookie on all subdomains is a security hole in this case.

The attack: A malicious Elmer could set up his site elmer.acme.com with some Javascript that reads the session cookie of anyone who visits his site and steals it. Then, if poor Bugs Bunny visits http://elmer.acme.com/ (Elmer's site), Elmer learns Bugs Bunny's session cookie. Now Elmer can pretend to be Bugs Bunny when visiting other subdomains (including Bugs' own site). That's no good.

If you somehow prevent Elmer from writing arbitrary HTML, Javascript, etc., to the website on his subdomain, then you might be OK. However, be warned this may be tricky to do securely, if you allow the users a lot of control over the content on their subdomain. You'll have to block a lot of stuff (including Javascript, Flash, Java, META tags, and maybe more).

Generally speaking, the reason to use multiple subdomains is to isolate multiple users from each other, so that one malicious user cannot harm other users, and so that a security failure by one user does not harm other users. If that's the reason you are using multiple subdomains, then your practice of using a single session cookie on all domains is insecure and should not be used.

In other words, most folks who are using multiple subdomains are probably in the first case, and thus I would expect that in many cases where multiple subdomains are used, it is not a good idea to expose the session identifier to all subdomains.

A better approach, that doesn't have these problems: Add a login page on acme.com. When users log in on acme.com, give them a session cookie that is scoped to acme.com only (no subdomains). This will be the secure session cookie.

When users visit a subdomain, you can do some tricks to authenticate them using their acme.com-session cookie and then give them a new cookie that is specific to the subdomain, without requiring them to log in again. The backend webserver can remember the association between the subdomain-specific cookie and the secure session cookie, so the webserver will be able to manage authentication in a way that the user doesn't notice.

This way, because you are separating your cookies by domain, you get better security. If one subdomain hosts malicious content, it learns only the session identifier for that subdomain, but it doesn't learn the session cookie for acme.com or for any other subdomains.

For instance, the secure session identifier for acme.com might be 7a3f...90 (cookie: SESSIONID=7a3f...90, scoped to acme.com). The session identifier for elmer.acme.com might be 09ac...b3 (cookie: SUBDOMAIN_SESSIONID=09ac...b3, scoped to elmer.acme.com), generated as SHA1(7a3f...9 || elmer.acme.com) = 09ac...b3. The session identifier for fudd.acme.com might be f067...85 (cookie: SUBDOMAIN_SESSIONID=f067...85, scoped to fudd.acme.com), generated as SHA1(7a3f...9 || elmer.acme.com) = f067...85. If elmer.acme.com is malicious, it cannot learn the secure session identifier or the session identifier for any other subdomain; it can learn the session identifier for its own subdomain, but that doesn't give Elmer any additional powers he didn't already have.

The only tricky bit is how to install these cookies onto the user's computer. I don't think it is a good user experience to ask/expect users to log in again for each subdomain they visit. Therefore, we should look for a technological solution that lets us transfer the session cookies across domains securely, without requiring the user to log in multiple times.

There are ways to achieve this, using iframes, postMessage, and/or redirection between domains. For instance, here is one approach. elmer.acme.com can have an invisible iframe that loads acme.com/authenticationhelper. The latter can use the secure acme.com-session cookie to authenticate the user. Meanwhile, the elmer.acme.com page can use postMessage to communicate to that iframe and ask it for a new session identifier that's good only for elmer.acme.com. Once elmer.acme.com receives this new session identifier, it can automatically set a session ID cookie that's scoped to elmer.acme.com, and now you're good. Here a key fact about postMessage is that the recipient of such a message can verify the domain that sent the message, which prevents spoofing and malicious attacks (acme.com can verify that it is elmer.acme.com who is requesting a subdomain-specific session identifier and respond with the appropriate session identifier for elmer.acme.com).

It's hard to figure out exactly what you're trying to do... but sounds like you might be making the problem harder than it needs to be. If I understand this post correctly, it explain how to share the same session between sub-domains, without having to generate your own session cookies. i.e. changing domain: :all to domain: "acme.com" might do the trick?