By default, Django offers protection against Cross-Site Request Forgery (CSRF) attacks by sending a CSRF token to webpages it generates, which is then sent back with requests to validate them. This is detailed here.
Django provides the csrf_exempt decorator to disable this behaviour. What are some good reasons programmers might want to use it?
This details why it could be dangerous, I'm interested in how it could be useful.
I'm looking for answers that are not obvious (e.g. not knowing how to use the CSRF protection or disabling it temporarily).
For instance, we use it for an interface where another party posts data programmatically. Thus, they can never get a csrf token. The page is, however, basic-auth secured.
Project I am working on has tiny embedded devices talking HTTP to a django application server over a VPN. The HTTP client on these is very primitive, so we disable CSRF.
Whenever your client sends a request to the server, some confidential information will be send along with the request. The CSRF token prevents a malicious site from abusing that information. Particularly, this prevents a malicious site from sending a forged request that uses your cookies and/or session to authenticate your client and authorize the action. Any information that is automatically and implicitly send on every request by your client is vulnerable to a CSRF attack (though not all information might actually be useful in such an attack).
The #csrf_exempt decorator can safely be used to avoid the CSRF protection mechanism if and only if the server-side actions that are the result from the request do not depend on the authentication and authorization that is sent implicitly by the client. Examples are token-based authentication and HTTP Basic authentication. For these forms of authentication, the client must explicitly sent the token or credentials for each request. If a malicious site forges a request, it cannot send the required authentication information to the server (unless a different vulnerability exposes that information), and the request is denied. In such cases, CSRF does not offer any extra protection.
Related
My website has an AJAX POST view that can be called from any page on the app (event tracking). This view is protected by CSRF. In some cases, the CSRF cookie is not set, and the POST call fails.
Instead of manually decorating all views with #ensure_csrf_cookie, I'm thinking of writing I created a middleware that enforces Django to set the CSRF cookie on all responses. Is this approach correct? Does it create a security flaw I'm not aware of?
Update: here is the middleware code:
from django.middleware.csrf import get_token
class ForceCsrfCookieMiddleware(object):
def process_request(self, request):
get_token(request)
No, there is no problem as long as you're not rendering the csrf token inside a form that posts to an external site (but that would be a problem anyways, no matter where you implement it). You can set it on a middleware, or some views, or on all views, it doesn't matter.
The CSRF protection is only made to ensure that the request is coming from your site. No matter how often you set the cookie, if the request includes the correct CSRF token it means that the request is indeed coming from your site, because only your site can access your cookies. (of course this only holds if you are not leaking the CSRF token to third parties, for example by sending it to other sites)
In few words, this is how it works:
The server sets a cookie with a random value in the response
Your site reads that value and sends it to the server when posting data
Since cookies can only be accessed from the same domain that set them, there is no way for another site to read that cookie. Therefore, whenever you receive a request that has the right csrf token, you are assured that that request is coming from your site.
For a very good explanation of CSRF, have a look at this article: http://www.gnucitizen.org/blog/csrf-demystified/
I have a e-commerce Django application that automatically verifies all incoming POST requests with CSRF token using the CSRFViewMiddleware.
Now, for payments, I'm using a payment gateway where I pass the relevant details along with the csrfmiddlewaretoken so that it is returned back to me when the transaction on 3rd party site is complete. So, when the user is re-directed back to my site, I get a
403 Forbidden
CSRF verification failed. Request aborted.
How do I fix this? Is there any way I can manually check csrftoken using request.POST.get('csrfmiddlewaretoken') or something like that.
I would prefer not to bypass csrf totally as I want it to be secure (atleast, as much as possible).
Edit I understand csrfmiddleware token needs to be passed in the header but I cannot do that as there are only limited things I can do with a 3rd party payment gateway.
From this snippet, I get a feeling that you may not quite understand what is CSRF:
I have a e-commerce Django application that automatically verifies all
incoming POST requests with CSRF token using the CSRFViewMiddleware.
That's part your problem right there. CSRF is only for those requests that are made from your site, to your site (see OWASP's definition of CSRF):
Cross-Site Request Forgery (CSRF) is a type of attack that occurs when
a malicious Web site, email, blog, instant message, or program causes
a user’s Web browser to perform an unwanted action on a trusted site
for which the user is currently authenticated.
You need CSRF tokens only on those forms that are generated by your site, and post to your site. In addition, any javascript code that sends a POST request should also be properly protected.
For all other end points - for example, if some payment provider is posting the result back to your application - you do not want to enable CSRF protection otherwise the requests will continue to fail.
I am creating an API with the Django Rest Framework. Users are still going to need to get a CSRF token to make POST, PUT, PATCH and DELETE calls. What is the best practice for the user initially getting a CSRF token? I am using TokenAuthentication. So I just need to allow the API to take and username and password and send back the Token. After that I don't need the CSRF token.
Do I have to add a step that will allow them to get CSRF token using a GET method call which will return a token?
I am looking for suggestions on how to best approach this.
With an API you are just about to open a gate to process requests on your server without any session and browser. CSRF tokens are just validating form requests to make sure it's sent from your website. As far as I know it's absolutely ok to turn off CSRF protection for APIs.
You can use csrf_exempt decorator for this.
Read this article to learn more about CSRF and Web API protection.
I have an app that I'm writing which authenticates against an Oauth 2.0 authorisation server. I'd like to test the parts that are accessible only after you've logged in but the Oauth server is an external dependency that complicates and make brittle my tests.
Any suggestions on how I should go about this? What the industry practices for something like this? My gut feel is to somehow mock out the server so that it allows access to the protected resources.
In case it matters, this is a Python webapp written using Flask.
I am using a custom oauth server which will run on my own domain and while it's possible to add some kind of sandboxing functionality as FoxMask has suggested, I'd much prefer being able to run the test without requiring an extra server running.
From the consumer (i.e. your application) side, the OAuth2 process can be separated in two parts:
the redirect from your application to the OAuth2 provider's "authorize" URL
the exchange of the "code" returned by the OAuth2 provider for an access token
For #1 all you need to test is that when you invoke the route that starts the authentication process the response returned is a redirect to the OAuth2 provider. This is easily accomplished with Flask's test client. The response should have a status code of 302 and a "Location" header set to the authorize URL for your OAuth2 provider. Note that you do not need to provider to be up, you are just testing that the response is a redirect, but you do not need to actually redirect.
Testing for #2 is a little bit more involved. Your Flask app has a special URL that is designated as the "redirect URL" for the OAuth2 provider to send you back the authorization code. You can just invoke this URL with the Flask test client passing a mock code and that has no issue.
The problem is that in the view function that handles your redirect URL you need to invoke the OAuth2 provider to exchange the auth code for an access token, and this is done synchronously. To prevent this transaction to happen you have to check app.config['TESTING'] and in that case skip the actual request and replace it with a fake response that includes a mock access token.
From then on you will need to also fake any additional calls into the OAuth2 provider that send the access token to request data.
If you are using an OAuth2 client library in your Flask app it may be easier to create the mock provider without having to create testing exceptions in your application. In my case I'm using rauth, and for this I have created a subclass of the OAuth2Service class that overrides the proper methods and responds with mock data that I have captured from a real session. Then in my test setup I just create the mock service and the application is fooled into thinking it is talking to a real server.
I hope this helps.
I have an application that has a "private" REST API; I use RESTful URLs when making Ajax calls from my own webpages. However, this is unsecure, and anyone could make those same calls if they knew the URL patterns.
What's the best (or standard) way to secure these calls? Is it worth looking at something like OAuth now if I intend to release an API in the future, or am I mixing two separate strategies together?
I am using Google App Engine for Python and Tipfy.
Definitely take a look at OAuth
It is quickly becoming the "de-facto" standard for securing REST APIs and a lot of big companies are using it, including Google, Twitter and Facebook just to name a few.
For Python on GAE you have two options:
The most straightforward way (IMHO) is using David Larlet's library for OAuth Support in Django available on BitBucket.
But since you're not using Django, maybe you want to take a look at the python-oauth2 library that's available on GitHub, and is considered the most up-to-date and unit-tested implementation of OAuth for Python 2.4+.
Either way I think you'd be much better using OAuth than rolling your own service security solution.
Securing a javascript client is nearly impossible; at the server, you have no fool-proof way to differentiate between a human using a web browser and a well-crafted script.
SSL encrypts data over the wire but decrypts at the edges, so that's no help. It prevents man-in-the-middle attacks, but does nothing to verify the legitimacy of the original client.
OAuth is good for securing requests between two servers, but for a Javascript client, it doesn't really help: anyone reading your javascript code can find your consumer key/secret, and then they can forge signed requests.
Some things you can do to mitigate API scraping:
Generate short-lived session cookies when someone visits your website. Require a valid session cookie to invoke the REST API.
Generate short-lived request tokens and include them in your website HTML; require a valid request token inside each API request.
Require users of your website to log in (Google Accounts / OpenID); check auth cookie before handling API requests.
Rate-limit API requests. If you see too many requests from one client in a short time frame, block them.
OAuth would be overkill in your current scenario (potentially insecure), in that it's designed to authorize a third party service to have access to resources on behave of the user.
Securing AJAX request via an authorized user
AFAICT, you are in control of the client, resources and authentication; so you only need to secure access to the URL's and possibly the communication between client and server via SSL [2].
So, use Tipfy's auth extension to secure your URLs:
from tipfy import RequestHandler, Response
from tipfy.ext.auth import AppEngineAuthMixin, user_required
class MyHandler(RequestHandler, AppEngineAuthMixin):
#user_required
def get(self, **kwargs):
return Response('Only logged in users can see this page.')
Securing AJAX request without an authorized user
If a user is unknown, then one could apply CSRF preventions to help protect the REST service from being called from an "unauthorized" client. Tipfy has this built-in to it's WTForms extension, but it's not AJAX. Instead, the session extension could be used to apply an "authenticity_token" to all calls, that needs to be verified on the server.