-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Varnish cookbook session cookie handling #4628
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,57 @@ If the ``X-Forwarded-Port`` header is not set correctly, Symfony will append | |
the port where the PHP application is running when generating absolute URLs, | ||
e.g. ``http://example.com:8080/my/path``. | ||
|
||
Cookies and Caching | ||
------------------- | ||
|
||
By default, a sane caching proxy does not cache anything when a request is sent | ||
with :ref:`cookies or a basic authentication header<http-cache-introduction>`. | ||
This is because the content of the page is supposed to depend on the cookie | ||
value or authentication header. | ||
|
||
If you know for sure that the backend never uses sessions or basic | ||
authentication, have varnish remove the corresponding header from requests to | ||
prevent clients from bypassing the cache. In practice, you will need sessions | ||
at least for some parts of the site, e.g. when using forms with | ||
:ref:`CSRF Protection <forms-csrf>`. In this situation, make sure to only | ||
start a session when actually needed, and clear the session when it is no | ||
longer needed. Alternatively, you can look into :doc:`../cache/form_csrf_caching`. | ||
|
||
.. todo link "only start a session when actually needed" to cookbook/session/avoid_session_start once https://github.com/symfony/symfony-docs/pull/4661 is merged | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A couple of todos got left here :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes. those PRs are not merged yet so i can't do that now. if we can wrap up the others really quick, i am happy to wait and update in a few days. otherwise i propose to merge already and hope that those PRs happen - or try to add the change in the respective PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. eliminated one of the TODOs . #4661 is still not merged, so i can't link to that. can we wrap those up? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think #4661 is kind of blocked because of the difficulty of the topic - you have 1 open question and 1 todo on that issue that I can't answer without some time to look into things. As an aside, for me, this smells like a bug or missing feature in Symfony. I think the PR symfony/symfony#6388 or issue symfony/symfony#6036 need to be finally pushed along - the functionality just isn't right. Of course, that's an even bigger task. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. okay. can we get this PR merged then? looks like the session start issue is a potentially long story. or do you not want todos in the doc code? should we create a new issue to remind us that when #4661 is merged we add a reference in this section of the doc. |
||
|
||
Cookies created in Javascript and used only in the frontend, e.g. when using | ||
Google analytics are nonetheless sent to the server. These cookies are not | ||
relevant for the backend and should not affect the caching decision. Configure | ||
your Varnish cache to `clean the cookies header`_. You want to keep the | ||
session cookie, if there is one, and get rid of all other cookies so that pages | ||
are cached if there is no active session. Unless you changed the default | ||
configuration of PHP, your session cookie has the name PHPSESSID: | ||
|
||
.. code-block:: varnish4 | ||
|
||
sub vcl_recv { | ||
// Remove all cookies except the session ID. | ||
if (req.http.Cookie) { | ||
set req.http.Cookie = ";" + req.http.Cookie; | ||
set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";"); | ||
set req.http.Cookie = regsuball(req.http.Cookie, ";(PHPSESSID)=", "; \1="); | ||
set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", ""); | ||
set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", ""); | ||
|
||
if (req.http.Cookie == "") { | ||
// If there are no more cookies, remove the header to get page cached. | ||
remove req.http.Cookie; | ||
} | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In practical terms, what should this mean to the user? I think it means that you're telling Varnish to yes be ok with caching requests that contain cookies. And so, as a user, you must be very careful to not rely on the session for any parts of your page where you return caching headers. If you violate this rule, then you will cache something with - for example - a user's username in it. Is this about right? I want to walk the user through this as much as possible. For me, it seems that you should be (as you elude to here) identifying which portions of your page need the session, isolating them into non-cached ESI fragments, then caching the whole page (or doing a complete opposite strategy where you isolate non-session-needing heavy pieces, then don't cache the whole page). The point is, this is non-trivial, so perhaps we need to walk them through a bit more tutorial-styled. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, I still mean everything I said, but most of what I said should be in the book. I still think we can add a few more details, like those I have in my first paragraph. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i tried to make this more explicit, and also added a warning at the end of the section. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So what's the result of this? Is this removing the Thanks - I'm asking stupid questions because I'm not a pro on this, and I know we are very close to making this very easy and useful :). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, the only cookie that will be retained is PHPSESSID. this is only about caching when there is no session. (together with what i removed, it would also be relevant to make Vary: Cookie actually useful as the cookie header becomes static with this cleanup). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i added a sentence above to hopefully explain what the idea is, and two comments that should make this more understandable |
||
|
||
.. tip:: | ||
|
||
If content is not different for every user, but depends on the roles of a | ||
user, a solution is to separate the cache per group. This pattern is | ||
implemented and explained by the FOSHttpCacheBundle_ under the name | ||
`User Context`_. | ||
|
||
Ensure Consistent Caching Behaviour | ||
----------------------------------- | ||
|
||
|
@@ -169,6 +220,8 @@ proxy before it has expired, it adds complexity to your caching setup. | |
.. _`Varnish`: https://www.varnish-cache.org | ||
.. _`Edge Architecture`: http://www.w3.org/TR/edge-arch | ||
.. _`GZIP and Varnish`: https://www.varnish-cache.org/docs/3.0/phk/gzip.html | ||
.. _`Clean the cookies header`: https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies | ||
.. _`Surrogate-Capability Header`: http://www.w3.org/TR/edge-arch | ||
.. _`cache invalidation`: http://tools.ietf.org/html/rfc2616#section-13.10 | ||
.. _`FOSHttpCacheBundle`: http://foshttpcachebundle.readthedocs.org/ | ||
.. _`User Context`: http://foshttpcachebundle.readthedocs.org/en/latest/features/user-context.html |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may we could go a step in this direction?
even if you drop the Cookie Header using Varnish, on the client side you can access them using JavaScript. For example you could extract the username from a cookie and replace the markup to display a custom welcome message.
In practice some parts of the site aren't cacheable for all users and sometimes it's not possible to solve this issues using JavaScript. For example consider you have a Form with a CSRF Protection. In this situation every user needs to get a unique token for the CSRF Protection. Here you can decide not the cache the whole Page. An alternative would be not to cache an ESI Request that is delivering the part of the Form that is responsible for the CSRF protection or decide to cache based on a user specific cookie. Using the Vary Header you can make sure that Varnish is caching based on another Header. Using Vary in combination with the Cookie Header allows you to fill up the Varnish cache with custom elements for every different cookie value. if the cookie value depends on the user, you are able to cache custom pages in varnish. Often there are a bunch of strategies with different advantages and disadvantages. Choosing the right caching strategy depdends on you use case, your Infrastructure and your Team.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dbu may go could use some parts of https://github.com/symfony/symfony-docs/pull/4628/files#r22298163 ? i just want to make sure that the reader get the idea that there a a bunch of caching strategies. filling up the varnish with user specific data is probably the worst one :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't think this cookbook should talk about general strategies to sort out cacheable from user content. there is the book chapter on caching that explains ESI. the topic of moving small things to javascript cookies is not specific to varnish but to caching in general and should rather go into #4661 or next to that. there is also #4141 which would cover the CSRF part of the topic.
ideally, both #4661 and #4141 would be wrapped up and merged, then this section would simply summarize and link information. if you want to add something to #4661 or next to it about moving information into javascript cookies that can be ignored by varnish, that would be useful information too.
#4141 is rather old however, so maybe i should just shorten this section and remove things that are too complicated / dangerous here.