-
Notifications
You must be signed in to change notification settings - Fork 887
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
Improve CSRF Support for Safety, REST, and Decoupling #1573
Comments
Oh, and I forgot to mention: I don't expect the code in pyramid_csrf to be taken wholesale, it's just a small proof of concept and I hope with this issue to get some feedback on the high level idea and whether or not it's something Pyramid would want to do before I bothered to dig into what the best way to integrate it into Pyramid itself and make a PR like that. If people think that the high level idea has merit then I'll see about making up a PR that implements it for real inside of Pyramid. |
Oh, and using this inside of a template is similar to how you use things today, an example in Jinja2: <input name="csrf_token" type="hidden" value="{{ request.csrf.get_scoped_token('accounts.login') }}"> Other enhancement to make that better could be:
|
I think every point here was addressed by the CSRF improvements in 1.7 except for 2. We don't allow for scoped tokens and we are still coupled to the session. I see no point in scoped tokens however decoupling the CSRF token from the session is something I'm happy to consider if we can do it in a bw-compat way (for example Anyway just some thoughts incase someone wants to work on this. |
Issues here should be fixed via #2854. |
@mmerickel Are the Vary headers set correctly too when CSRF protection is enabled or is this something that can/ought to be done manually? |
@rmoorman Good catch, the vary headers are not set automatically by the default policies. I would be happy to evaluate solutions to that problem but they would vary (pun intended) between the different storage mechanisms. For example for the session-based policies it is up to the session to do the right thing whereas the cookie-based policy may want to do its own thing if it makes sense. In general you should expect to do it yourself right now. |
@mmerickel I wouldn't have a good idea where to start in order to let the CSRF policies apply the correct |
Well the "storage" policy is dictating how the CSRF token is tracked between requests as well. Usually via some form of cookie. If you look at the |
@mmerickel I see. Django for example does roughly the same (annotating the request object when the token is retrieved from somewhere through it's csrf.middleware.get_token function). Which other methods do you think are necessary? Isn't the |
The current CSRF support in Pyramid suffers from a few problems:
ISession
which has exception raising session methods.Vary: Cookie
for example orVary: Authorization
), however the current CSRF system doesn't do anything about this.I extracted some CSRF stuff from an application I'm writing in Pyramid and sketched out some basic ideas for how I think CSRF should be implemented. That's available (without tests or documentation) at https://github.com/dstufft/pyramid_csrf.
The basic idea there is:
ISession
, it adds it's own interfaceICSRF
(andICSRFFactory
), theICSRF
instance is made available asrequest.csrf
.CookieCSRF
which just stores the tokens it generates inside of a dedicated cookie, another isSessionCSRF
which just stores the tokens it generates inside of the session, and the final isLegacySessionCSRF
which doesn't store or generate tokens itself at all, and instead it just dispatches to the legacy methods onISession
.Vary
headers to the response to ensure that caches don't serve a page with a CSRF token cached inside of them.config.registry.unregisterUtility(provider=ICSRFFactory)
.A key part in being able to make this on by default is that any particular view can exist in 3 states:
i. No CSRF is configured for this view, in this case attempting to use an "unsafe" action (POST, PUT, etc) will raise a
HTTPMethodNotAllowed
without any vary headers.ii. The view is configured to be exempt, in this case the CSRF system is no-oped for this view and no CSRF checking is done and no vary headers are added. This is also what happens for every view if the CSRF system is disabled.
iii. The view is configured to be csrf protected, in this case the CSRF system will kick in, check the CSRF token, and either allow the view code to be executed if things check out or will raise a 403 error otherwise. In either case a Vary header is added based on the type of CSRF backend being used.
The example code I wrote isn't meant to be drop-in ready for Pyramid, as it has a number of problems that I know of offhand:
Vary
based onCookie
, but that should be dependent on the backend.config.unset_csrf_factory()
instead ofconfig.registry.unregisterUtility(provider=ICSRFFactory)
.@view_config
or something like that.CookieCSRF
, but probably Pyramid would want to have a dynamic default where it look to see if aISessionFactory
has been registered, and if it has then default toLegacySessionCSRF
, and if it hasn't then defualt toCookieCSRF
. Maybe it'd also be possible to make those legacy csrf methods onISession
optional, and if a sesion factory is registered that doesn't have those it'd useSessionCSRF
instead.There are some unrelated to the mechanism itself, but still improvements to the CSRF system found in pyramid_csrf as well that would be good to get into Pyramid either way:
HMAC_sha512(unscoped_token, scope)
, and even the unscoped token could be implemented that way, just with a scope of""
.Origin
header, and if failing that will fall back to theReferer
header. This check will ensure that when your CSRF tokens depend on the value of some cookie (whether session or jsut a csrf cookie) that a subdomain or a root domain cannot submit a CSRF request since their origin wouldn't match. This particular check has been in Django for some time, and there is a research paper showing that on same-domain HTTPS sites the referer header is only missing in 0.2% of cases (See https://github.com/django/django/blob/a3473454ada67c0a16efeabcb78950641d4ac93c/django/middleware/csrf.py#L134-L162 and https://sparrow.ece.cmu.edu/group/731-s11/readings/csrf.pdf).The text was updated successfully, but these errors were encountered: