Thread: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
[PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Marti Raudsepp
Date:
Hi list, I noticed that most of the forms on the Postgres community site don't use CSRF protection. That's bad -- CSRF should be on by default. I went through all the views that handle POST data and didn't find any that should handle input from cross-domain requests. But CSRF exceptions, if any, should be decorated with @csrf_exempt (from django.views.decorators.csrf). Also available from my Github repo: https://github.com/intgr/pgweb Regards, Marti
Attachment
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Magnus Hagander
Date:
On Tue, Oct 30, 2012 at 9:54 PM, Marti Raudsepp <marti@juffo.org> wrote:
Hi list,
I noticed that most of the forms on the Postgres community site don't
use CSRF protection. That's bad -- CSRF should be on by default.
I went through all the views that handle POST data and didn't find any
that should handle input from cross-domain requests. But CSRF
exceptions, if any, should be decorated with @csrf_exempt (from
django.views.decorators.csrf).
Also available from my Github repo: https://github.com/intgr/pgweb
Hi!
The diff appears to be reversed. But that's easy enough to deal with during commit.
Have you verified that it works with django 1.2 as well? The production deployment is on that quite old version still...
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Marti Raudsepp
Date:
On Wed, Oct 31, 2012 at 7:29 PM, Magnus Hagander <magnus@hagander.net> wrote: > The diff appears to be reversed. But that's easy enough to deal with during > commit. No, it's not reversed. I'm removing the explicit @csrf_protect decorators because all views are now protected by default. > Have you verified that it works with django 1.2 as well? The production > deployment is on that quite old version still... Yeah, I developed and tested this on Django 1.2 Regards, Marti
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Magnus Hagander
Date:
On Wed, Oct 31, 2012 at 6:44 PM, Marti Raudsepp <marti@juffo.org> wrote:
On Wed, Oct 31, 2012 at 7:29 PM, Magnus Hagander <magnus@hagander.net> wrote:No, it's not reversed. I'm removing the explicit @csrf_protect
> The diff appears to be reversed. But that's easy enough to deal with during
> commit.
decorators because all views are now protected by default.
Oh. Pardon my confusion. You are right, of course.
> Have you verified that it works with django 1.2 as well? The productionYeah, I developed and tested this on Django 1.2
> deployment is on that quite old version still...
Good.
So, one more thought. Is this going to break if the form is cached? That is, the original form at e.g. http://www.postgresql.org/community/ for the surveys is cached. That means that the CSRF token that's on the form actually ends up being cached. Is the CSRF token going to be valid in those cases, and is it actually going to protect us?
Forms that come in over https are safe, because we never cache those. Forms re-rendering because they were sent by POST as well, they are not cached. But a form that's over http and where the form itself uses GET will get cached as it is now.
AFAICT it will break, because the CSRF stuff uses a cookie that wouldn't be set, so there wouldn't be anything to match the token against. Or am I missing something here?
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Marti Raudsepp
Date:
On Fri, Nov 2, 2012 at 1:31 PM, Magnus Hagander <magnus@hagander.net> wrote: > So, one more thought. Is this going to break if the form is cached? That is, > the original form at e.g. http://www.postgresql.org/community/ for the > surveys is cached. That means that the CSRF token that's on the form > actually ends up being cached. Is the CSRF token going to be valid in those > cases, and is it actually going to protect us? Yeah, that's true. But it should be a matter of flushing the Varnish cache, right? There are no cache policy headers on these responses, so browsers will generally revalidate the page. But now that you mention it, there is another caching impact: accessing this page causes the user's cookies to be changed, and due to "Vary: Cookie", it will prevent the caching of any subsequent page fetches for this user in Varnish, even on other pages (for 1 full year by default). Of course the above also affects any users who logged in -- since the csrftoken cookie is served without the "secure" flag, the cookie is also present in any non-secure requests. Does this also impair Varnish "grace mode", when the backend server is down? Regards, Marti
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Magnus Hagander
Date:
On Fri, Nov 2, 2012 at 3:23 PM, Marti Raudsepp <marti@juffo.org> wrote:
Magnus HaganderOn Fri, Nov 2, 2012 at 1:31 PM, Magnus Hagander <magnus@hagander.net> wrote:Yeah, that's true. But it should be a matter of flushing the Varnish
> So, one more thought. Is this going to break if the form is cached? That is,
> the original form at e.g. http://www.postgresql.org/community/ for the
> surveys is cached. That means that the CSRF token that's on the form
> actually ends up being cached. Is the CSRF token going to be valid in those
> cases, and is it actually going to protect us?
cache, right? There are no cache policy headers on these responses, so
browsers will generally revalidate the page.
No, we'd need to disable the caching of the page completely, if we want the cookie to be passed along.
For a "pure form", that will only affect performance, and probably not too bad. But they need to be identified and excluded.
For combined pages, like the /community/ page, it's a slightly bigger problem. Disabling caching of it disables grace mode, which also makes that page completely unavailable in the event of a backend or network failure. For a regular form it's not a big problem sinc the form wouldn't work anyway, but that page is used as a navigation page as well... I'm not sure if we have any other such pages (other than the search, but we can certainly disable CSRF for search, right?)
But now that you mention it, there is another caching impact:
accessing this page causes the user's cookies to be changed, and due
to "Vary: Cookie", it will prevent the caching of any subsequent page
fetches for this user in Varnish, even on other pages (for 1 full year
by default).
No, that's not a problem. We strip cookies in varnish by default. We only support them over https...
Of course the above also affects any users who logged in -- since the
csrftoken cookie is served without the "secure" flag, the cookie is
also present in any non-secure requests.
We only log users in over https, not http. All login-required pages are (should be) behind https only, and the session cookie has the secure flag set. Any cookies present on a http request are just removed.
Does this also impair Varnish "grace mode", when the backend server is down?
Yes, turning off caching turns off that functionality as well, which is why it's something we'd like to avoid.
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Marti Raudsepp
Date:
On Fri, Nov 2, 2012 at 4:32 PM, Magnus Hagander <magnus@hagander.net> wrote: > No, that's not a problem. We strip cookies in varnish by default. We only > support them over https... Ahhh! That explains everything. I wasn't aware of the magic that happens on the proxy level. I thought you were relying on Django to not send cookies when not necessary, and the proxy respected the HTTP headers sent by Django like a conforming HTTP proxy. The attached patch adds @csrf_exempt to the survey view and removes csrf_token from the template. > if we have any other such pages (other than the search, but we can certainly > disable CSRF for search, right?) Search uses GET parameters so it already bypasses CSRF. Regards, Marti
Attachment
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Magnus Hagander
Date:
On Fri, Nov 2, 2012 at 4:09 PM, Marti Raudsepp <marti@juffo.org> wrote:
Thanks - applied. Please help me keep an extra eye out on things the next couple of days to see if we broke something :)
On Fri, Nov 2, 2012 at 4:32 PM, Magnus Hagander <magnus@hagander.net> wrote:Ahhh! That explains everything. I wasn't aware of the magic that
> No, that's not a problem. We strip cookies in varnish by default. We only
> support them over https...
happens on the proxy level. I thought you were relying on Django to
not send cookies when not necessary, and the proxy respected the HTTP
headers sent by Django like a conforming HTTP proxy.
The attached patch adds @csrf_exempt to the survey view and removes
csrf_token from the template.
Thanks - applied. Please help me keep an extra eye out on things the next couple of days to see if we broke something :)
> if we have any other such pages (other than the search, but we can certainlySearch uses GET parameters so it already bypasses CSRF.
> disable CSRF for search, right?)
Ah, good point.
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Magnus Hagander
Date:
On Mon, Nov 5, 2012 at 2:12 PM, Magnus Hagander <magnus@hagander.net> wrote: > On Fri, Nov 2, 2012 at 4:09 PM, Marti Raudsepp <marti@juffo.org> wrote: >> >> On Fri, Nov 2, 2012 at 4:32 PM, Magnus Hagander <magnus@hagander.net> >> wrote: >> > No, that's not a problem. We strip cookies in varnish by default. We >> > only >> > support them over https... >> >> Ahhh! That explains everything. I wasn't aware of the magic that >> happens on the proxy level. I thought you were relying on Django to >> not send cookies when not necessary, and the proxy respected the HTTP >> headers sent by Django like a conforming HTTP proxy. >> >> The attached patch adds @csrf_exempt to the survey view and removes >> csrf_token from the template. > > > Thanks - applied. Please help me keep an extra eye out on things the next > couple of days to see if we broke something :) Ugh. This broke the admin interface form to access varnish. I've mad eit exempt. Is there any actual reason why we need it in the admin interface, since you need to have a session logged in as an administrator already to access it? It also broke the purging API. Also made exempt, but that appears to not solve the problem. Do I need to do something more than add @csrf_exempt to a view functoin to make it not broken? The error message talks about the referrer header - but surely that shouldn't be a requirement when oyu've set @csrf_exempt? And it broke the bug reporting form, also fixed in a separate commit. We may well have missed more parts :( Clearly neither one of us tested this patch very well. If we run into any further issues (assuming we can solve the one above), we should probably revert the whole thing. But let's hope we can make it work.. --Magnus HaganderMe: http://www.hagander.net/Work: http://www.redpill-linpro.com/
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Marti Raudsepp
Date:
On Wed, Nov 7, 2012 at 7:49 PM, Magnus Hagander <magnus@hagander.net> wrote: > This broke the admin interface form to access varnish. I've mad eit > exempt. Is there any actual reason why we need it in the admin > interface, since you need to have a session logged in as an > administrator already to access it? Yes, you *especially* need CSRF protection in the admin interface. Anything that performs privileged actions and is authenticated via cookies without CSRF protection is vulnerable. Say for example I send you a bug report with a link to http://my-evil-server/page.html . Not suspecting anything, you follow the link. This page contains a hidden <form method=POST action="https://www.postgresql.org/admin/...">, with custom fields based on the actions I want to perform. This form is submitted on page load via JavaScript into a hidden iframe -- all without you realizing it. If you have an authenticated session on postgresql.org, then your browser will happily pass your personal cookie on to postgresql.org, along with any form fields dictated by the attacker -- thus the attacker can use your session to perform any actions you are authenticated to perform. Such as changing your account password. This is a major vulnerability, not just security masturbation. > It also broke the purging API. Also made exempt, but that appears to > not solve the problem. Do I need to do something more than add > @csrf_exempt to a view functoin to make it not broken? The error > message talks about the referrer header - but surely that shouldn't be > a requirement when oyu've set @csrf_exempt? It seems that the problem is the @ssl_required decorator -- it returns a new wrapped view without copying over attributes of the original view, such as "csrf_exempt". Changing the decorator order won't work either because that will confuse PgMiddleware. I'll send a patch to fix @ssl_required some time soon. > We may well have missed more parts :( Clearly neither one of us tested > this patch very well. "It all worked on my computer" ;) But my setup is plain Django. I admit, I should have put more thought into it, once you told me about the cookie magic that happens in Varnish. Regards, Marti
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Magnus Hagander
Date:
On Wed, Nov 7, 2012 at 7:59 PM, Marti Raudsepp <marti@juffo.org> wrote: > On Wed, Nov 7, 2012 at 7:49 PM, Magnus Hagander <magnus@hagander.net> wrote: >> This broke the admin interface form to access varnish. I've mad eit >> exempt. Is there any actual reason why we need it in the admin >> interface, since you need to have a session logged in as an >> administrator already to access it? > > Yes, you *especially* need CSRF protection in the admin interface. > Anything that performs privileged actions and is authenticated via > cookies without CSRF protection is vulnerable. Fair enough. In that case, it really needs to get fixed... >> It also broke the purging API. Also made exempt, but that appears to >> not solve the problem. Do I need to do something more than add >> @csrf_exempt to a view functoin to make it not broken? The error >> message talks about the referrer header - but surely that shouldn't be >> a requirement when oyu've set @csrf_exempt? > > It seems that the problem is the @ssl_required decorator -- it returns > a new wrapped view without copying over attributes of the original > view, such as "csrf_exempt". Changing the decorator order won't work > either because that will confuse PgMiddleware. > > I'll send a patch to fix @ssl_required some time soon. Thanks. >> We may well have missed more parts :( Clearly neither one of us tested >> this patch very well. > > "It all worked on my computer" ;) Really? Because the purging form doesn't work on my local machine... Which does not go through varnish at any point, for example. Same goes for the purging API endpoint - doesn't work locally either. So if those work for you locally, then there is definitely something else afoot.. (The bug form worked fine on my computer, so that one was pretty hard to catch in testing - but a good way to test it is to just turn off cookies and see if things that should work when not logged in still work) --Magnus HaganderMe: http://www.hagander.net/Work: http://www.redpill-linpro.com/
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Marti Raudsepp
Date:
On Wed, Nov 7, 2012 at 9:11 PM, Magnus Hagander <magnus@hagander.net> wrote: >> "It all worked on my computer" ;) > > Really? Because the purging form doesn't work on my local machine... > Which does not go through varnish at any point, for example. Well I meant that half-jokingly. I don't have a complete development environment. When I navigate to that page, I get "ERROR: schema "pgq" does not exist". With that said, I can't see why these views/forms wouldn't work with CSRF. They're not doing cross-domain requests or anything. I will need to drill deeper. Regards, Marti
Re: [PATCH] Enable CsrfViewMiddleware -- make CSRF protection required by default
From
Magnus Hagander
Date:
On Wed, Nov 7, 2012 at 8:35 PM, Marti Raudsepp <marti@juffo.org> wrote: > On Wed, Nov 7, 2012 at 9:11 PM, Magnus Hagander <magnus@hagander.net> wrote: >>> "It all worked on my computer" ;) >> >> Really? Because the purging form doesn't work on my local machine... >> Which does not go through varnish at any point, for example. > > Well I meant that half-jokingly. > > I don't have a complete development environment. When I navigate to > that page, I get "ERROR: schema "pgq" does not exist". Hmm. That was *supposed* to be handled by varnish_local.sql. But I see now that it tries to actually look into the table that doesn't exist. The actual form would work - it's just the listing of what's in the queue right now that's now broken. That could just be rendered as a completely empty listing in the case that there is no pgq installed - that should be an easy fix. > With that said, I can't see why these views/forms wouldn't work with > CSRF. They're not doing cross-domain requests or anything. I will need > to drill deeper. Me either - it looked fine when reviewing the patch. Just not when testing it (in production) :) --Magnus HaganderMe: http://www.hagander.net/Work: http://www.redpill-linpro.com/