Problem/Motivation
The example $cookie_domain variable in settings.php fails for sites with subdomains and does not meet RFC 2109 standards. When $cookie_domain contains only one dot, each subdomain like http://de.example.com and http://fr.example.com issues its own session cookie to the user which prevents the session remaining active when switching between domains.
Current implementation:
$cookie_domain = 'example.com';
Correct version:
$cookie_domain = '.example.com';
To reproduce the problem:
1) Create two Drupal sites with subdomains (Example: http://de.example.com and http://fr.example.com).
2) Log into one of the sites.
3) Switch to the other site. You will be logged out.
Proposed resolution
The proposed solution is to add a period before the domain name for example.com and to add documentation that requiring a preceding dot meets RFC 2109 standards.
$cookie_domain = '.example.com';
Users who cannot apply the patch should add a preceding . to their $cookie_domain.
Remaining tasks
- Commit to Drupal 8
- Backport to Drupal 7
- Backport to Drupal 6
User interface changes
No changes.
API changes
No changes.
Original report by reglogge
In settings.php the site administrator can define a $cookie_domain to ensure that users remain logged in when switching between several subdomains that follow the pattern http://de.example.com, http://fr.example.com and http://en.example.com. This is mostly used when running a multilingual site with domain prefixes.
This only works when $cookie_domain contains at least two dots '.' however. So setting $cookie_domain to
$cookie_domain = 'example.com';
as it is offered in settings.php as an example doesn't work.
The culprit seems to be this code in bootstrap.inc (lines 604ff.)
// Per RFC 2109, cookie domains must contain at least one dot other than the
// first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
ini_set('session.cookie_domain', $cookie_domain);
}
where we check whether there are at least two dots in $cookie_domain.
I'm not sure how to fix this. Either we could eliminate the check for at least two dots or modify the comment and example in settings.php so that it reads something like this:
/**
* Drupal automatically generates a unique session cookie name for each site
* based on on its full domain name. If you have multiple domains pointing at
* the same Drupal site, you can either redirect them all to a single domain
* (see comment in .htaccess), or uncomment the line below and specify their
* shared base domain. Doing so assures that users remain logged in as they
* cross between your various domains. Make sure to always start
* $cookie_domain with a leading dot.
*/
# $cookie_domain = '.example.com';
Since RFC 2109 states on page 4 that "An explicitly specified domain must always start with a dot", it seems that amending settings.php is the safer route. Patch attached.
I'm setting this to major since this makes multilanguage sites pretty unusable when using domain prefixes.
Comment | File | Size | Author |
---|---|---|---|
#24 | cookiedomain-doc-1005570-23.patch | 759 bytes | reglogge |
#20 | cookiedomain-doc-1005570-20.patch | 742 bytes | reglogge |
#15 | cookie_domain-1005570-15.patch | 2.67 KB | reglogge |
#11 | cookie_domain_5.patch | 1.72 KB | reglogge |
#3 | cookie_domain_4.patch | 1.73 KB | reglogge |
Comments
Comment #1
reglogge CreditAttribution: reglogge commentedbot...
Comment #2
reglogge CreditAttribution: reglogge commentedTo clarify: When $cookie_domain contains only one dot, each subdomain like http://de.example.com and http://fr.example.com issues its own session cookie to the user which prevents the session remaining active when switching between domains.
The attached patch removes a whitespace issue against the patch in the OP.
Comment #3
reglogge CreditAttribution: reglogge commentedThis patch adds an additional check for the leading dot for a user-specified $cookie_domain in bootstrap.inc. It adds a dot if it has been omitted by the user. Not sure if this is babysitting though.
With this patch, the user could specify either
example.com
or.example.com
and the cookie domain would always be set to.example.com
which is the correct value.For IP-addresses or domains not containing at least one dot in the middle of them (like
localhost
or.localhost
) no cookie domain is set.There is quite a bit of discussion around this here #458704: Don't automatically remove "www." from admin-set cookie domains, but that issue is currently against Drupal 6.x-dev.
Comment #4
reglogge CreditAttribution: reglogge commentedJust clarifying the title.
Comment #5
Tor Arne Thune CreditAttribution: Tor Arne Thune commentedI understand this could be a problem. This is something I came across with a multilingual site of mine. I had no idea I had to add a leading dot. It would be great to get this committed, so that others don't get exposed to the same problem.
Comment #6
Tor Arne Thune CreditAttribution: Tor Arne Thune commentedIt would be great to get this into 7.1, as default.settings.php already has a change for this file (removing typo). As it is now, this issue could really create confusion for multi-lingual site administrators. The easy fix would be to just change the comment documentation in default.settings.php, but adding a conversion in bootstrap.inc would also help a lot for those users who don't read comments.
Comment #7
tmk1 CreditAttribution: tmk1 commentedSame issue in Drupal 6.x since upgrade to 6.17
#comment without . in example variable is present also in current 6.20 release
Comment #8
reglogge CreditAttribution: reglogge commented#3: cookie_domain_4.patch queued for re-testing.
Comment #10
Tor Arne Thune CreditAttribution: Tor Arne Thune commenteddefault.settings.php has changed in HEAD since this last patch was made. A new patch needs to be rolled.
Comment #11
reglogge CreditAttribution: reglogge commentedRerolled patch attached...
Comment #12
Marko B CreditAttribution: Marko B commentedFor me there is one more issue since upgrading from 6.16 to 6.20. I did use the .example.com but what happens it when i am logged in as user 1 when i switch languages user gets logout every time, like cookie is set only for one language. I'll opetn a separate issue for this.
Comment #13
c960657 CreditAttribution: c960657 commentedSetting $cookie_domain is an advanced feature, so we don't need to babysit too much. But if we can make it blend in with the existing code-path, I guess it's fine. E.g. by ltrim'ing the dot to begin with and then only add the leading dot directly in the ini_set('cookie_domain', ...) call. Perhaps replace explode(':', $cookie_domain) with strtok($cookie_domain, ':') to skip the following line.
A small cleanup is to replace to count(explode(...)) with substr_count().
Using ord($cookie_domain) !== 46 to check for a leading period is very obscure :-)
Comment #14
Tor Arne Thune CreditAttribution: Tor Arne Thune commentedComment #15
reglogge CreditAttribution: reglogge commentedI rerolled the patch with a more conventional way (using substr()) of determining if the user-defined $cookie_domain starts with a period.
Other changes:
The result of this is that $cookie_domain will now always be set with a leading period as mandated by RFC 2109. The table shows what happens if a user defines $cookie_domain in settings.php or $cookie_domain is auto-created by Drupal.
Comment #16
c960657 CreditAttribution: c960657 commentedIs the "if" necessary? Aren't we sure that the domain never has a leading period, so that it must always be added?
Since we now ltrim() the period if it is there, it doesn't matter whether there is a leading dot or not, so the text “Make sure to ...” is a bit misguiding. But it is probably a good idea to mention one format just to prevent that users have to go elsewhere to look it up, e.g. by adding “(with a leading period)” after “specify their share base domain”. Well, just an idea.
This is not related to your patch, but perhaps you could change it. I think it is bad code style that the $cookie_domain variable is used to hold a string, then it is reused to hold an array, and then again it uses a string. This can be avoided e.g. by replacing
$cookie_domain = $_SERVER['HTTP_HOST'];
with$cookie_domain = strtok($_SERVER['HTTP_HOST'] ':');
Comment #17
c960657 CreditAttribution: c960657 commentedOh, one other thing (outside the scope of this issue, so feel free to ignore this):
The condition
!is_numeric(str_replace('.', '', $cookie_domain))
only works for IPv4 addresses. I suggest that we celebrate World IPv6 Day by adding support for IPv6 too, e.g. by changing the check tofilter_var($cookie_domain, FILTER_VALIDATE_IP))
.Comment #18
sun#17 (adding IPv6 support) is a separate issue.
I think I ran into this issue a couple of times in the past years, so I'm tempted to demote this issue to normal.
The changes to settings.php and $cookie_domain look bogus to me. That said, the docs about $cookie_domain could use some love, indeed.
Comment #19
catchThis really looks like just a documentation issue to me, demoting from major since like sun says it's an advanced feature. Don't see any reason to add code to catch domains missing the dot really.
Comment #20
reglogge CreditAttribution: reglogge commentedWell then, let's just fix the documentation. Patch attached.
Comment #21
catchComment #22
Tor Arne Thune CreditAttribution: Tor Arne Thune commentedHow about adding "Make sure to always start the $cookie_domain with a leading dot, as per RFC 2109." for all those wondering why. More eyes will be on this change than any other file in Drupal core (except for maybe .htaccess), as a change in
default.settings.php
can make them think that they may have to update their settings.php files accordingly.Comment #23
webchickSeems like a good suggestion.
Comment #24
reglogge CreditAttribution: reglogge commentedHere goes...
Comment #25
Tor Arne Thune CreditAttribution: Tor Arne Thune commentedLooks good :)
Comment #25.0
JuliaKM CreditAttribution: JuliaKM commentedadding issue summary
Comment #25.1
JuliaKM CreditAttribution: JuliaKM commentedadding doc clarification
Comment #26
catchCommitted to 8.x, moving to 7.x for webchick to consider.
Comment #27
webchickI think this makes sense. People are going to whinge a bit about a change to default.settings.php, but the way it's written now is actually a bug.
Committed and pushed to 7.x.
Comment #28
webchickAnd this actually seems worthy of a change notice.
Comment #29
reglogge CreditAttribution: reglogge commentedChange notice added at http://drupal.org/node/1325380.
Comment #30
Tor Arne Thune CreditAttribution: Tor Arne Thune commentedLooks good :)
Comment #31.0
(not verified) CreditAttribution: commentedChanged nameof original reporter to correct one.
Comment #33
AlexBorsody CreditAttribution: AlexBorsody as a volunteer commentedThis is deprecated, maybe consider rewriting.
RFC 6265 section 4.1.2.3
For example, if the value of the Domain attribute is "example.com", the user agent will include the cookie in the Cookie header when making HTTP requests to example.com, www.example.com, and www.corp.example.com. (Note that a leading %x2E ("."), if present, is ignored even though that character is not permitted, but a trailing %x2E ("."), if present, will cause the user agent to ignore the attribute.)
Comment #34
davenok CreditAttribution: davenok commentedSo, we are trying to implement the GSA (Google Search Appliance) to crawl our Drupal site. However, we have not had any success with getting the device authenticated to the site. We have been working with google support engineer who has identified this as the issue.
Set-Cookie: SSESSf893ea1f149fa728663bc7c5088af4ea=kctTZiPh3LO9SAjOgxrbT8f1vPRql6SyWic41GVjivU; expires=Fri, 25-Mar-2016 23:33:35 GMT; Max-Age=2000000; path=/; domain=.subdomain.mydomain.com; secure; HttpOnly
Domain is specified with leading dot at the beginning. But, during GET request, GSA doesn't submit this cookie to the portal as it fails to match with the URL https://subdomain.mydomain.com/.
This is not an expected behavior and we already have a bug for it #6846787. Currently it's not fixed and the only possible workaround I can propose - change cookie domain to "domain=subdomain.mydomain.com" (w/o leading dot) on the portal side. It should resolve the issue.
However, if I modify my settings.php for the cookie_domain setting and leave the leading . out, I am unable to authenticate to the site at all.
Is there a way to change this behavior?