On a new Drupal 9 install, the session cookie of a logged in user, does not have a "SameSite" attribute at all.
This attribute should at least be explicitly set to Lax.
As far as I am concerned though, I would set the value to Strict, at least if I have a security sensitive site/application.
So, my question is: Is there a valid reason for not setting this cookie attribute at all?
Furthermore, is there a valid reason for not setting this cookie attribute to the default secure option of "Strict" (with the ability to be relaxed/configured maybe through a setting or in settings.php)?
I know that this issue is also Symphony related. I am not super familiar with the core, so I am trying to start an educated discussion on the topic and include better informed persons too.
Possible usefull links:
https://www.drupal.org/project/drupal/issues/3027872
https://www.drupal.org/forum/support/module-development-and-code-questio...
Release notes snippet
Drupal now adds 'Samesite: Lax' as a session cookie attribute by default. This is configurable in default.services.yml
| Comment | File | Size | Author |
|---|---|---|---|
| #94 | Screenshot 2023-03-03 at 15-16-15 Status report Drupal.png | 56.67 KB | znerol |
| #86 | 3150614-86-9.5.x.patch | 4.32 KB | pfrenssen |
Issue fork drupal-3150614
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3150614-set-samesite-on
changes, plain diff MR !2887
Comments
Comment #2
cilefen commentedComment #3
vagelis-prokopiou commentedI am attaching an initial patch that sets the attribute to Strict by default.
The best strategy would be something different, I suppose. Something like the following:
$options['cookie_samesite'] = (overriding condition) ? 'Lax' : 'Strict';Comment #4
berdirStrict means that if you click on a link on foo.org that goes to drupal.org, then you would *not* send the session cookie and you would not be logged in. So strict is IMHO never an option for the session cookie, it has to be at most Lax.
Even Lax has caused problems for us for example in combination with payment gateways that POST the user back to Drupal, then the session is missing, the user has no access to the order and payment fails.
Comment #5
cilefen commentedAgreed, Lax should be the default. It actually is the default in some modern browsers if none is set.
Comment #6
vagelis-prokopiou commentedLax is a good default indeed. It should be configurable of course, in case we want to change it for security reasons.
Comment #7
winn commentedAttached is a version of the patch with the attribute set to "Lax", as a slightly better default.
Comment #8
berdirIs that really the default and not actually forcing that value?
Comment #9
hanoiiI am also in then need for something like this configurable, as I need to set it to 'None' so that a third party iframe (rocketchat) I am including in my site is able to make an authenticated request to my site from the iframe. However, None only works if the cookie is secure, so I am doing:
on an overridden SessionConfigurator service.
Comment #11
mxr576Enhancing cookie policy settings is a request by every security firm that we meet on projects, so I am changing the priority of this task.
There is, like it was mentioned earlier also. If you set Strict then one-time login links stop working from web based email clients hosted on different domain than the site. I had to fix this problem by changing Strict to Lax months ago. This is the comment that I left in my code, I hope it helps.
Related to cookie policies, I also have an in-review patch for SimpleSAML PHP module because it also conflicted with the enhanced cookie policy settings.
Comment #12
mxr576Since my previous comment, I also found a core related bug which could also block resolving this issue, see #3187037: Lost Symfony features cased by missing parent calls in SessionManager
Comment #13
blazey commentedIt would be nice to be able to change the setting with a service parameter.
Comment #14
alexpottNow getting a warning in Firefox:
Cookie “SESS3e09ff6d94c856f40d453871b91a99ad” will be soon rejected because it has the “SameSite” attribute set to “None” or an invalid value, without the “secure” attribute. To know more about the “SameSite“ attribute, read https://developer.mozilla.org/docs/Web/HTTP/Headers/Set-Cookie/SameSite
Bumping this to critical because of that.
Comment #15
cilefen commentedDrupal 7 just shipped this 😖
Comment #16
cilefen commentedThis is #13 with the code style adjusted and spellcheck exceptions.
Comment #17
cilefen commentedThe Drupal 7 version makes this configurable in settings.php and documents it there.
Comment #18
cilefen commented@alexpott: Did you set the samesite option to 'None' in the container (as in services.yml) when you tested?
Comment #19
cilefen commentedDocument in default.services.yml. Technically, defaulting to 'Lax' is a BC-break. AFAIK the D7 patch defaults to 'None'.
Comment #21
alexpott@cilefen nope - wasn’t using the patch. My comment was about a warning you get with a Drupal site on Firefox without this patch and justifying why it should be critical.
Comment #22
cilefen commentedApologies: I misread that comment obviously. It makes more sense to me now.
Update the scaffold file.
Comment #24
cilefen commentedAdd test coverage to SessionConfiguration and use
cookie_samesitethroughout for consistency.Comment #25
cilefen commentedComment #26
cilefen commentedComment #27
cilefen commentedThis currently looks a lot different from D7's implementation, mostly because D9 uses the Symfony session component.
!$request->isSecure() && isset($options['cookie_samesite']) && $options['cookie_samesite'] == 'None'Comment #28
cilefen commentedThis
emulatesmimics the Drupal 7 behavior, by letting the container value then an INI value take precedence, and falling back to to 'None' or NULL (no value).Comment #29
alexpott@cilefen nice to see green test runs on this issue.
I think we need at least new sites to be built with lax as the default. Changing default.services.yml is fine because it only affects new installations. For existing installations they will need update their services.yml file and we need to add something to system_requirements() telling people to update it and that none - the current value is not recommended.
I'm not sure that this fallback is relevant for D8 / D9. If you've set samesite in php.ini we're going to ignore at the moment anyway. Feels like additional complexity for not much gain.
Comment #30
alexpottFWIW D8 / D9 already completely ignore php.ini session.cookie_* variables or we overwrite them as far as I can see. For example, we overwrite the lifetime in \Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage::regenerate() and httponly in \Drupal\Core\DrupalKernel::bootEnvironment()
Comment #31
cilefen commented@alexpott Thank you for the feedback. Just so I'm clear, are you advocating to remove the INI config fallback and
!$request->isSecure() ? NULL : 'None';or only the former (INI)?Comment #32
DeFr commentedHaven't read everything here just yet but quickly responding to #31 : do note that right now, D8/D9 are honoring the ini_set('session.cookie_samesite') and that's been the recommended workaround in a bunch of issues for example in the commerce ecosystem, see for example https://www.drupal.org/project/commerce/issues/3051241 . I'm pretty sure there's a bunch of sites out there in PHP 7.3 setting it that way.
Comment #33
cilefen commented@DeFr Noted. I'm leaning toward simply not modifying SessionConfiguration::getOptions which should keep the current behavior but taking the Drupal-configured value only if one exists.
Comment #34
alexpott@DeFr thanks for that - going to try to work out how that is working and document here.
Comment #35
cilefen commented@alexpott
It looks like
NativeSessionHandlerNativeSessionStorage does an ini_set if it encounters an allowed session config in the config that is passed to it. So otherwise the system value prevails.Comment #36
cilefen commentedMake the implementation simple and direct.
Sketch out the system requirements.
Comment #37
cilefen commentedConstrain the requirements phases. I am not sure if these are correct.
Comment #39
tsplash commentedUpdate to also set the samesite attribute when destroying a session cookie. Browser fails to remove the cookie across CORS if this isn't set.
Comment #40
cilefen commentedThere are other cookie settings listed in NativeSessionStorage::setOptions we could simply pass through if we were to document them in default.settings.yml.
Thus, #3248319: Add cookie_path for session cookies.
Comment #41
bradjones1Re: #29, I am working on a progressively decoupled site that also leverages OAuth and
Laxis the "most" you can do if you need attributes in the session loaded when users are redirected back to the site, e.g. during OAuth2.I agree also that this is a great chance to defer as much as we can to the Symfony session handler and that this might be more an inline documentation item than anything.
Comment #43
ollaankoodeis commentedRerolled the patch for the 9.3.x version.
EDIT: Fixed patch below. Removed changes to sites/default/default.services.yml because patch was not applying with it. I don't know how to make changes outside core folder in case of core patch?
Comment #44
cilefen commentedComment #45
ollaankoodeis commentedComment #46
ranjith_kumar_k_u commentedFixed CS errors.
Comment #47
Christopher Riley commentedI am getting a failure when patching via composer update so I manually grabbed it and patched by hand and got the following:
patching file core/assets/scaffold/files/default.services.yml
patching file core/lib/Drupal/Core/Session/SessionConfiguration.php
patching file core/lib/Drupal/Core/Session/SessionManager.php
patching file core/misc/cspell/dictionary.txt
Hunk #1 FAILED at 1183.
1 out of 1 hunk FAILED -- saving rejects to file core/misc/cspell/dictionary.txt.rej
patching file core/tests/Drupal/Tests/Core/Session/SessionConfigurationTest.php
-> more core/misc/cspell/dictionary.txt.rej
--- core/misc/cspell/dictionary.txt
+++ core/misc/cspell/dictionary.txt
@@ -1183,6 +1183,7 @@ safa
sameline
samename
sameorigin
+samesite
sata
savepoints
sayre
Suggestions?
Comment #48
cilefen commentedDo a formal reroll, or, apply the patch onto a clean checkout of Drupal 9.4.x, manually update that dictionary file as appropriate and create a new patch.
Comment #49
Sbonder commentedComment #50
alexpottThis needs fixing to comply with coding standards i.e.
Comment #51
andypostUpdated patch, added description
Comment #52
murilohp commentedAbout #51:
Just a nitpick here, could you create a placeholder for the URL? something like:
'description' => t('This attribute should be explicitly set to Lax or Strict. See <a href=":url" target="_blank">PHP documentation</a>', [':url' => 'https://www.php.net/manual/en/session.configuration.php#ini.session.cookie-samesite']),I think it's better when we read the code.
I think we could avoid this else statement here, maybe doing something like:
Both comments are just suggestions, and I'm ok to move on without changing anything. I'll move this back to needs work to see what you think.
Comment #53
alexpottFor good practice let's add the $strict argument to in_array(). We really should have a PHPCS rule about this.
I think this should be:
I don't understand why we would replace the invalid value with the word invalid. That seems to be losing helpful information.
Comment #54
andypostThe reason is that default value for the most distros is empty string, which is useless to display
Comment #55
murilohp commentedThat's a good idea, it would be nice to have an issue upstream to address this.
Just applying the suggestion here.
Comment #56
murilohp commentedI've missed your comment @andypost, do you think
Not set, is enough?Forgot to change the title, here's a new patch. I'll move this to NR to see what you think.
Comment #57
murilohp commentedComment #58
andypostThank you, now only change record required to rtbc
Comment #59
anagomes commentedComment #60
anagomes commentedCreated the CR, moving back to needs review!
Comment #61
cilefen commentedI think you can set the configuration value to 'None' also, and there are reasons for having to use None.
Comment #62
murilohp commented@cilefen, I think I've missed that part, the patch has some documentation mentioning "None", but reading #14, Firefox is aparently warning about "None", I think we need to change the documentation here right?My bad here, actually it's fine to have "None" as cookie.samesite value, but we need to guarantee "Secure" attribute when the samesite is set to "None".
Comment #63
berdirNone gives a warning *if* the cookie is not marked as secure: "without the “secure” attribute". It's ok to set it to None and there are use case that break with Lax, typical examples include POST submissions from payment gateways back to your site. And Strict is in fact going to break _many_ use cases, including all offsite payment gateways that redirect back as well as any direct link to the site from elsewhere, like e-mails. Users will not be logged in on that first request.
IMHO, this should not add a requirement warning.
Comment #64
quietone commentedThis should use @see, https://www.drupal.org/docs/develop/standards/api-documentation-and-comm.... There is another comment in the patch that needs to be changed too.
Comment #65
berdir@see should only be used on standalone docblock definitions, if it's parts of a sentence then "see" is correct, see also the example just below.
Comment #66
alexpottI agree with @Berdir None + Secure should not produce a warning either. I think given that browsers are defaulting to Lax for cookies that don't set SameSite setting our default to Lax makes sense. Unfortunately this will make the requirement logic more complex again.
Comment #67
murilohp commentedThank you for your explanation @berdir!
This patch just adds the "None" to avoid the warning, I thought about making a validation when the "none" is set and the "secure" attribute is not set, but AFAIK, drupal does not allow "session.cookie_secure" setting to be override. So I think the secure will always be set right?
Comment #68
alexpott@murilohp - it's not that simple - here's what Drupal does for the secure cookie setting...
Therefore
Nonewill only work if you're forcing your site to use https. If you allow non-https traffic then you'll need to set SameSite to Lax. I think maybe something like:I'm not sure about the
To me it feels just on the limits of okay for complexity / length.
Comment #69
berdirChecking the request object in hook requirements is not going to work when these requirements are checked with drush/CLI. That will mess with https://www.drupal.org/project/monitoring for example.
I'd expect that in 2022, non-secure will mostly just be relevant for development and test sites, but maybe I'm wrong, not sure.
Comment #71
pfrenssenPHP_SAPI !== 'cli'check prevents this from throwing false positives on the command line. I added a short explanation so this is documented.Comment #72
pfrenssenHere's a version of the patch from #71 compatible with Drupal 9.3.
Comment #73
pfrenssenComment #77
cilefen commentedThe other cookie configuration values have defaults documented with
@default. I guess we should do that here too? The default for SameSite is no value. How would we indicate that. Is it "null"? It can't be "None" because that is actually a specific SameSite option.An example of the
@defaultdocumentation:Comment #78
cilefen commentedComment #79
bradjones1"Undefined" or "not set"?
Comment #80
cilefen commented"Undefined" in this context seems to imply something random could happen. I would prefer "not set" or "no value".
Comment #81
pfrenssenFixed coding standards and remarks from comments #77-80 in the MR. Here is a backport of the latest iteration to D9.5.
Comment #82
muaz7731Test out the patch from #81. it help out the SameSite cookie problem for me. +1 for RTBC
Comment #83
pfrenssenLast test failure was unrelated. Rebased on latest 10.1.x.
Comment #84
mikesimmons commentedUnfortunately, #81 does not apply to Drupal 9.5.3.
Comment #85
chi commentedNitpick. This issue is for Drupal 10 which means we can use PHP 8.1 syntax here.
The latter could be split into multiple lines.
Comment #86
pfrenssenComment #87
znerol commentedThanks!
Comment #89
catchOK the test coverage looks neat and the docs are fine. Looks like a lot of browsers, if not all, are defaulting to 'Lax' rather than none, so this shouldn't be disruptive, but better to get this into 10.1.x early.
I'm slightly weary about offering 'Strict' given Berdir's comments that it would break everything, but... maybe there's a use case and we probably want to allow configuration between 'Lax' and 'None' anyway.
I added a release note since this changes scaffold files.
Comment #90
cilefen commentedThe change record looks incorrect.
Comment #91
cilefen commentedI made some edits to https://www.drupal.org/node/3275352. Have a look.
Comment #92
znerol commentedI think the change record was correct before. Commit
a3bddae4doesn't change the default - neither for existing nor for new sites. In order to change the default value for thesession.cookie_samesite, it is necessary to set the container parameter incore/core.services.yml. The commit only touchessites/default/default.services.yml.The following change is necessary in order to influence the default behavior (for new and existing sites):
Comment #93
cilefen commentedI'll reverted the changes but it says things like "Drupal core will begin to warn if the session cookie SameSite is not set to Lax or Strict" which I do not think are true.
Comment #94
znerol commentedThat's in fact what happens.
php core/scripts/drupal quick-start, then navigate to/admin/reports/status#warning, this is what I get:Comment #95
znerol commentedI've updated the CR with the correct way to fix the warning.
Comment #96
cilefen commentedAgain, "Drupal core will begin to warn if the session cookie SameSite is not set to Lax or Strict" is untrue. I've looked at the commit. "None" is an allowed value under one condition.
Comment #97
alexpott@znerol - it's a bit trickier than that... completely new sites where sites/default/services.yml gets created from sites/default/default.services.yml will have it set to Lax and will not have a warning.
I do think we need a quick follow-up though. I think we should add
cookie_samesite: Laxtocore.services.ymlin it'ssession.storage.optionsso that quickstart sites have the correct default.Comment #98
znerol commentedI tried the web installer as well as the quick-start script. Neither of them copies
default.services.ymltoservices.yml. Both of them will copydefault.settings.phptosettings.phpthough. So the install behavior is different forservices.ymlandsettings.php. I wonder whether we should fix that inconsistency.Comment #99
znerol commentedIt looks like this has a purpose, see #2547447: Stop creating services.yml by default.
Comment #101
catchLet's do #97 here, I was also under the mistaken impression that default.services.yml kicks in for newly installed sites without manual copying.
Reverted so all the changes can go back in togher.
Comment #103
cilefen commentedComment #104
rpayanmI added the #97's suggestion, please review.
Comment #105
alexpott#2547447: Stop creating services.yml by default makes this really tricky. Because it means sites don't have a sites/default/services.yml - that means that the whole
"existing sites can stay as they are and new sites get the new value"assumption won't work.That said, I think the current approach is fine given https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/Sam... - it says
so defaulting to Lax makes sense as that is what most modern browsers are doing anyway.
I think the CR will need to document how to unset it in case someone is relying on the current behaviour and we need to call this out in the release notes.
Comment #106
znerol commentedThanks @rpayanm, the
SameSiteattribute is now present on the session cookie for all sites. Going to revert the CR to @cilefen version and add instructions on how to modify the default.Comment #108
catchCommitted/pushed to 10.1.x (again), thanks!
Comment #109
andypostThank you, published CR
Comment #110
quietone commentedThis is marked for change record updates and I think that happened because znerol restored the CR to a previous version. Removing tag.
Comment #111
ralphvdhoudt commentedRerolled patch against 9.4
Comment #112
ralphvdhoudt commentedRerolled patch against 9.4.10
Comment #113
ralphvdhoudt commentedPrevious patch for 9.4 had patch for sites/default/default.services.yml which is scaffolded