-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[2.2] [Session] Mixed-mode sessions #3247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
See also #2853 |
I'm not entirely sure I understand what vector this closes yup? Session attributes are stored server side and never transmitted over the transport - only the session id is transmitted over the transport protocol, in a cookie. Could you explain the exact vector please? |
You already named it. The cookie can be intercepted and faked, which gives me the possibility to hijack the session. The secure cookie, on the other hand, can't be intercepted. |
I am sorry but I still don't see that. A session cookie simple contains an ID as it's data. No other data or attributes are stored. The session attributes are only stored server side. Of course, anyone can write a cookie and change the session ID regardless of the transport, but you would have to know the ID of the session in order to hijack it. Simply running a site in |
Of course data is stored server side. Ultimately the problem is caused by many websites running some pages using HTTP and others using HTTPS. Imagine I visit page A using HTTPS and get a session cookie X. The page displays sensitive information I entered previously. Now I visit page B, which uses HTTP, so suddenly cookie X is transmitted in cleartext and can be intercepted. A malicious user can copy and reproduce the cookie X locally and visit page A using HTTPS to access my sensitive information. The server can't verify that the malicious user is not me, because the cookie value is the same, and the IP, user agent string and other potentially identifying information can be faked. |
@bschussek Would the security aspect not be covered by session_set_cookie_params? Roughly translated in Symfony to: <?php
$sess = new Session(new NativeFileSessionStorage(null, array('cookie_secure'))); Or are you looking for additional functionality along with security? |
@cboden No, because in your case AFAIK the session is HTTPS-only. I was proposing a solution for mixed HTTP/HTTPS environments |
I still don't understand how this brings overall security as this ticket assumes that only sensitive data might be stored and retrieved from session attributes, which is clearly not the case - sensitive data will surely be persisted elsewhere too. The only secure way to protect that data is to ensure it's it retrievable only by |
@Drak We are talking about two orthogonal things. Of course, sensitive information can be stored elsewhere. Still, the key to look up this sensitive information (like the customer's ID) is usually stored in the session. Having two separate session namespaces protects developers (or teams) from their own errors. Once I consciously decide that some information, e.g.
My point lies in the conscious decision that is required. Right now, things like this happen, sensitive data is being leaked on insecure pages without anyone taking notice. |
I can see your point, basically having two sessions. The Secure one is only available when HTTPS is used, the other one is always present. Its similar to a plain-to-secure transition but this time preserving the previous session? |
There is no import involved. You, the developer, decide for each attribute whether to access it via the Note that this doesn't prevent a developer completely from accessing secure attributes. If you read all attributes from the session and iterate over them, this will obviously include the secure attributes. But neither is this a standard use case. I think this wouldn't be a big problem, but something to be documented and to be aware of when doing such things. |
@bschussek Could this functionality be achieved by composition without editing the Session file?: <?php
// bootstrap - (assuming $request is an HttpFoundation Request object)
if ($request->isSecure()) {
$secure = new AttributeBag('secure');
$session->registerBag($secure);
}
// later in script
if ($loggedIn) {
$session->getBag('secure')->set('user_id', $user->getId());
} |
I added a small example in the description in order to highlight why I think this feature is strongly necessary. Please correct me if there are better ways to solve this issue. |
It would even be possible to persist the secure session attributes encrypted, that would prevent the |
If an attacker obtains your session cookie (via an insecure site), what prevents him from accessing a secure site with your cookie, and then consequentially accessing the secure attributes as well? |
@schmittjoh if I understand @bschussek right, the call to |
@snc Exactly. (on both points) |
I extended the description above again for an example (both before and after introducing this feature). |
Ok, so we basically have two cookies (the session cookie for HTTP/HTTPS, and an additional cookie HTTPS only). Sounds good to me. I would like to suggest a small change though. Namely, not adding getSecureAttribute and variants, but rather a secure parameter to the "set" method (
|
Ah, that makes it clear. Great plan! You can make a shopping site where the shopping section and your basket is HTTP and the checkout section is HTTPS. Also like the idea of @schmittjoh of using an parameter, this makes it almost the same as setcookie where you have the secure parameter. |
@schmittjoh You suggest adding the parameter only to |
I would advocate that the attribute name should still be unique (e.g. there At this point, your question is just an implementation detail. We could use
|
I see. Fine by me in that case. I think we should definitely throw an exception though. Apart from that we should look into implementing this in a way such that secure attributes can optionally be encrypted too if the developer desires that. |
I have a very simple answer to give here but before I do, since a lot of other topics have been talked about, I would like to explain some stuff about session security. I know most of you know more about this topic than me but I want to address these points so we are all on the same page. Firstly the concept of encryption of a session. This has two parts. The session data and the session ID which is passed by the browser back to the server are separate. At no point is the session data ever exposed to an attacker except where data is deliberately output in the view. So the very concept of mixing encrypted and non-encrypted session data is strange and unnecessary. The decision to encrypt back-end storage an application implementation detail. If one was storing credit card data you would/should encrypt that data so if someone got physical access or hacked the server the data would not be exposed. However, were talking about getting direct access to the database here - either via SQL injection which means your application is broken anyway, or at a completely different level, i.e. server filesystem/login level - at which point security is completely breached. If one wishes to encrypt the session then that is what the proxy mechanism is for and I already documented it at php.net here: http://docs.php.net/SessionHandler (see Example #1). This reminds me I was supposed to add some example code to the documentation at symfony.com. Please see the Symfony docs on the proxy mechanism. The next thing I read here was something about "if an attacker got your session ID" as if it's easy - but if someone does get your session ID, then the game is over (unless we do other things I will explain in a minute). Getting a session ID is extremely difficult unless you perform man in the middle attacks on non-http connections or the application does something stupid (like expose the session ID in the URL or have The next is "Session Fixation" where you fix other details to the session ID - for example by client IP, IP subnet - that way the session can only be accessed by the IP or subnet that created it/logged in. You can also hash some details from the client browser signature (name, version, etc). This one is a very good protection because there are so many different browser versions and attacker would need to not only get your session ID but also your browser and IP metrics, and be able to connect from your IP or subnet. Next, obviously one's application needs to be free from XSS by correct output filtering but Javascript has SOP so the session ID not available to 3rd party sites running JS on the same page - in any case, XSS is a risk and needs to be fixed there. These are all things that can (and should) be done at application level. We do this in Zikula sessions for example - sessions can be fixed to IP, IP subnet, and browser signature. OT, we also have cookie signing, so a client cannot interfere with a cookie - this is not relevant with session cookies since there is nothing to forge (there is no data except the session ID). I do have that on my list of PRs to-do for Symfony Sessions. I will give my reply in the next comment which addresses the concerns of @bschussek and shows why there is no security issue or attack vector as described. |
So the concern of this ticket is that a user may authenticate via I have made a gist to demonstrate this: https://gist.github.com/2620468 Please clear your browser cookies for localhost before running the script. The code shows the cookies received by the client browser and you can clearly see that the browser does not send the secure cookies over HTTP requests. From the PHP script side, it is important, where it matters, not to create new cookies we want to be secure, over a non secure connection. This would mean checking the http request environment before issuing a cookie. Again, this could be done with routing because a login should always be over HTTPS anyway and if it is, the transmission of the cookie is over HTTPS back to the client so this is covered. There should be no HTTP-only route to a login page. If one is protecting against MITM attack, then even though the session cookie is only transmitted once for the lifetime of the cookie from server to client, it should not be done in plain-text, but sent over SSL. |
@Drak I'm aware of that and listed your solution even in the description under "Solution A". Would you mind to re-read? |
If you want to encrypt all sessions transparently you can use the suhosin extension if available. But this is a little bit off topic... |
Drupal does not split the session it is a little bit trickier what it does. You get two session cookies, your insecure session ID which is transmitted over both HTTP and HTTPS and your secure session ID which is HTTPS only. When reading your session the following scenarios are considered:
The results is that stealing the insecure cookie is useless: on a properly configured site will never let you execute anything privileged. |
An ability for client to have 2 unrelated sessions(secure & insecure, like in @chx description) looks weird. @bschussek proposal about HTTPS-only attributes bag sounds good for me because user will have only one session. |
@fabpot what do you think about this feature ? |
If you use this split mode then don't allow for HTTP logins. HTTP is for anonymous only. |
The Drupal use-case is a little bit different but still somewhat related to what was proposed here. Let me illustrate this with the following example: Consider a typical company website with a busy public front page and an extranet for business partners. In order to prevent trivial drive-by industry espionage it was decided that the extranet only should be reachable via HTTPS. At the same time it seemed to make little sense to also enforce encrypted connections on public parts of the website. Thus there is a set of paths where HTTPS always should be used and maybe another set of paths where HTTPS is not desired (for performance reasons, but I consider that a mere historical argument). When mixed mode SSL is turned on in Drupal, the results are:
Mixed mode SSL as implemented in Drupal is to prevent against simple drive-by attacks. It does not help against active man-in-the-middle (e.g. SSLstrip) though. Also note that by default Drupal sets |
Thank you for the insight @znerol. What I propose above is effectively what you describe. |
@webmozart Has there been any progress on this proposal or specific plans to implement it? Support within the framework for mixed mode session handling would solve a real PITA issue so I'm certainly in favor of it. 👍 |
For the record, mixed mode session support has been removed from Drupal 8 core. |
I would suggest to not implement this: it adds complexity (thus opens new opportunities for security bugs), for something that is solved in a far better by using https-only session cookie. |
I agree this concept has been obsoleted by the introduction of LetsEncrypt and the universal push to encrypt the entire web. In 2018 everyone should just go https-only. |
Now that the sessions are being reworked by @Drak, I would like to introduce another feature which in my opinion is critical for secure websites: Secure session attributes.
How can sessions be hijacked in mixed HTTP/HTTPS environments?
Solution A: Secure session cookie
The only possible solution right now is to set
session.cookie_secure
to on. But then HTTP pages cannot access the session.Solution B (proposed): Split sessions
The second idea is to split the session into an insecure and a secure area like this:
This is intended for the case when
session.cookie_secure
is off. The session cookie is always transmitted, so both HTTP and HTTPS pages can access it.Within the session, a nested bag is stored that contains the secure attributes. In order to gain access to this secure bag, a key is needed. This key is transmitted in a second cookie, the "security cookie", with
secure
set to on (i.e. transmitted via SSL only).Attributes in the outer container (=normal session) can be accessed
Attributes in the secure bag can be accessed
Developers can chose to
API
Implementation
The value of the security cookie could be calculated as a hash of
microtime(true)
session_id()
So the session could look like this:
If you erase the security cookie (or if a hacker hijacks your session and sends the wrong security cookie), a new secure bag will be created, leaving the old one untouched.
How this fixes our initial example
The text was updated successfully, but these errors were encountered: