csrf protection and bookmarks

90 views
Skip to first unread message

Peter Santoro

unread,
Jun 21, 2013, 11:20:32 AM6/21/13
to pylons-...@googlegroups.com
I'm writing my first Pyramid application and I'm trying to strike a balance between security and useability.  My environment is Python 3.3.2, Pyramid 1.4.2, and Cherrpy 3.2.4.  The Intranet application uses AuthTktAuthenticationPolicy and validates users via win32security.LogonUser.

I've also implemented csrf protection using UnencryptedCookieSessionFactoryConfig for some views.  A new csrf_token is created in the forbidden_view for unauthenticated users before redirecting to the login_view.  The login_view calls pyramid.session.check_csrf_token at the start of form processing.  If the user's login credentials validate, a new csrf_token is created.

I have some questions with respect to best practices regarding csrf protection and bookmarks.

I've written code inside my login_view to rewrite the referrer/came_from url if it contains a csrf_token to use the newly created login csrf_token - if and only if - the user is attempting to login, has a valid application account, and their Windows login credentials have been validated via win32security.LogonUser.  If I don't rewrite csrf containing urls at successful login, csrf protected bookmarked views expectedly fail.

Bookmarked views not protected via @view_config check_csrf kwarg work as expected.  For example, if a user is logged out and accesses such a bookmark, they are forced to successfully login before being redirected to the chosen bookmark.

However, when a user is logged out and accesses a bookmarked view protected via @view_config check_csrf kwarg I'm seeing the following behavior (i.e. browser displays 404 Not Found):

-----
serving on 0.0.0.0:8080 view at http://127.0.0.1:8080

route matched for url http://localhost:8080/name/tom%20jones/None/None/ALL/include-payments/prod/imgret/?csrf_token=a77f342f15d74d0bb10596a5ccf11bec00d5b708; route_name: 'view.name', path_info: '/name/tom jones/None/None/ALL/include-payments/prod/imgret/', pattern: '/name/{name}*extra', matchdict: {'extra': ('None', 'None', 'ALL', 'include-payments', 'prod', 'imgret'), 'name': 'tom jones'}, predicates: ''

debug_authorization of url http://localhost:8080/name/tom%20jones/None/None/ALL/include-payments/prod/imgret/?csrf_token=a77f342f15d74d0bb10596a5ccf11bec00d5b708 (view name '' against context <PredicateMismatch at 0x2148998404 Not Found>): Allowed (NO_PERMISSION_REQUIRED)

debug_authorization of url http://localhost:8080/name/tom%20jones/None/None/ALL/include-payments/prod/imgret/?csrf_token=a77f342f15d74d0bb10596a5ccf11bec00d5b708 (view name '' against context <PredicateMismatch at 0x2148998404 Not Found>): Allowed (no authorization policy in use)
-----

If I remove the @view_config check_csrf kwarg from the view used in the above trace and instead call pyramid.session.check_csrf_token on entry to the view callable, I get the behavior I was expecting (i.e. a logged out user will be redirected to the login_view where the url is rewritten (for a successful login) to contain a new csrf_token giving them access to the bookmarked view).

My questions:

1) Should I not be rewriting urls which contain csrf_tokens during a successful login to support csrf protected bookmarked views?  What are the risks in doing so?  Is there a better/safer way to handle csrf protected bookmarked views or is this just a bad idea to begin with?  (I'm sure my users will complain if bookmarks don't work as they expect.)

2) With respect to the above trace, why is the view apparently not found when the @view_config check_csrf kwarg is used?  If I remove the @view_config check_csrf kwarg from the view callable and call pyramid.session.check_csrf_token directly in the view callable (and no other changes are made), I get the behavior I'm expecting (i.e. user is redirected to the forbidden_view, which forces a login; if login is successful, the bookmarked url is rewritten with a new csrf_token, and then redirection to the bookmarked view succeeds).

3) Is it best practice to create a new csrf_token in the forbidden_view for unauthenticated users before redirecting to the login_view, where it is subsequently checked before processing login input?

Thank you,

Peter

Vincent Catalano

unread,
Jun 21, 2013, 1:07:17 PM6/21/13
to pylons-...@googlegroups.com
Peter,

I think you are going about handling CSRF tokens wrong. You should be using tokens only for form submissions and HTTP POSTs. The Pyramid documentation covers this a little bit here: http://docs.pylonsproject.org/projects/pyramid/en/1.0-branch/narr/sessions.html#preventing-cross-site-request-forgery-attacks. You should have a token generated as a hidden input field for any form on your site. For requests such as GET requests, I would let Pyramid's authorization and authentication policy handle your security here.

1. The idea of a CSRF token protected view is a bit unnecessary. If your application security is configured properly, you shouldn't need any additional security as part of the URL.

2. I'm not sure what the problem is with your trace, however - like I mentioned earlier - I would advise against CSRF tokens in your URL parameters.

3. No, this is not a good practice. Don't worry about creating a CSRF token on a forbidden view.

I hope this helps you out a bit.

-Vincent





--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discus...@googlegroups.com.
To post to this group, send email to pylons-...@googlegroups.com.
Visit this group at http://groups.google.com/group/pylons-discuss.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Vincent Catalano
Software Engineer and Web Ninja,
(520).603.8944

Peter Santoro

unread,
Jun 21, 2013, 7:18:04 PM6/21/13
to pylons-...@googlegroups.com
Vincent,

Thank you for your prompt response.  After reviewing some additional information about csrf tokens on https://www.owasp.org, it appears that using them on GET requests is definitely not a good idea and isn't compliant with RFC 2616.  I should have thought of that, as I know GET requests are supposed to be safe.  I've already refactored my code to remove the offending logic.

Take care,

Peter
Reply all
Reply to author
Forward
0 new messages