Django CSRF when backend and frontend are separated - python

After searching the internet, people normally deal with this situation---the front-end is generated by django view function which can send user the cookie of csrf token. When user has a request to server using ajax, people can rewrite the ajaxSend behavior which send the csrf to server.
However, my situation is that my front-end is totally separated from back-end, ie, my front-end is in a dedicated server running nginx, and I only have one html providing all of the different pages using hashbang. My back-end is running in different server using different domain name, and in this case, how does client obtain the csrf cookie? My back-end only provided json api return.
Thank you.

This post is quite old but for people who still wander here:
For client-server setups, such as native desktop and mobile clients (and separate front end like the OP's case), it is best to use Django Rest Framework's Token Authentication. Link

If you look at the CRSF token source: you can see that all the csrf_middleware does it check the cookie against the post value. You just need to get the post value back to your server since the cookie should of already been set though ajax. If you look at the template tag source you can see that it is just taking the variable out of the context. Either stick it in your response by pulling it out of the context if it is available or calling the context processor directly. Now you just need to send it back as the POST variable crsf_token.

Lets say, frontend has the domain frontend.example.com, and backend domain backend.example.com. (If you are something like Django rest framework)
If you can use there are two ways you can enable security layer i.e.,. CSRF Protection or CORS
For CORS,
pip install django-cors-headers
and then configuring this to INSTALLED_APPS, MIDDLEWARE_CLASSES and add the frontend domain to CORS_ORIGIN_WHITELIST.
CORS_ORIGIN_WHITELIST = (
'frontend.example.com'
)
CORS will block any http request arising from any domains other than frontend.example.com
For CSRF,
CSRF_COOKIE_DOMAIN = ".mydomain.com"
and if you are using an Angular App, do like below,
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.withCredentials = true;
and then add headers while make a http request.
headers : {
"x-csrftoken" : $cookies.csrftoken
}

Related

How to pass request over Django channels WebSocket and call Django view

I'm working on a single page application with Django, and would like to use WebSockets, and therefore Channels. To keep things simple, I think I want to handle all server communication over a WebSocket alone, rather than adding XHR (XML HTTP Request) into the mix. I'm using channels from the get-go since there will be a lot of data pushed from the server to the client asynchronously.
With regular Django, a conventional request made to https://example.com/login or https://example.com/logout or whatever and the Django URL router will decide what view to send it to. Instead, I would like to have the user perform their action in the client, handle it with Javascript, and use the WebSocket to send the request to the server. Since I'm using Django-allauth, I would like to use the provided Django views to handle things like authentication. The server would then update the client with the necessary state information from the view.
My question: how can I process the data received over the WebSocket and submit the HTTP request to the Django view? My channels consumer would then take the rendered HTML and send it back to the client to update the page or section.
I can picture what would happen using XHR, but I'm trying to avoid mixing the two, unless someone can point out the usefulness in using XHR plus WebSockets...? I suppose another option is to use XHR for authentication and other client initiated requests, and use the WebSocket for asynchronously updating the client. Does this make any sense at all?
Update: It occurs to me that I could use requests from PyPi, and make an sync_to_async call to localhost using credentials I received over the WebSocket. However, this would require me to then handle the session data and send it back to the client. This seems like a lot more work. That said, I could maintain the sessions themselves on the server and just associate them with the WebSocket connection itself. Since I'm using a secure WebSocket wss:// is there any possibility for hijacking the WebSocket connection?
Check out this project that gives the ability to process a channels websocket request using Django Rest Framework views. You can try to adapt it to a normal Django view.
EDIT: I am quoting the following part of the DCRF docs in response to #hobs comments:
Using your normal views over a websocket connection
from djangochannelsrestframework.consumers import view_as_consumer
application = ProtocolTypeRouter({
"websocket": AuthMiddlewareStack(
URLRouter([
url(r"^front(end)/$", view_as_consumer(YourDjangoView)),
])
),
})
In this situation if your view needs to read the GET query string
values you can provides these using the query option. And if the view
method reads parameters from the URL you can provides these with the
parameters.
#hobs if you have a problem with the naming of the package or the functionality is not working as intended, please take it up with the developers on Github using their issue tracker.

Django Rest Framework without authentication + GET only

I am developing a back-end for a webpage using Django Rest Framework. The webpage will be public, and it will only fetch information from this service. Thus, I have to deploy both service and webpage.
Since the webpage is public access (without any type of login) I can avoid having to set up the SSL stuff. However, by default, the DRF comes with the browsable API and the login field. I know I can remove the browsable API, but is it enough?
For instance, the configurations I would have would be:
(removing the BrowsableAPIRenderer)
'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.JSONPRenderer',
'rest_framework_csv.renderers.CSVRenderer', )
and:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = (
'GET',
'HEAD',
'OPTIONS',
)
I am using https://github.com/ottoyiu/django-cors-headers for the CORS stuff.
Would this be enough to avoid unwanted login atempts? Is there any specific way to disable this option?
What 'DEFAULT_PERMISSION_CLASSES' shoul I use?
Best regards and thanks for any help!
If you have a login, but you don't have SSL, then your users are vulnerable to packet sniffing of credentials on many wifi and ethernet networks. Such a vulnerability can be trivially exploited with the Firesheep firefox plugin. Due to users' habit of reusing passwords, you could end up compromising their security to a more critical website. This is very unfortunate. It isn't entirely your problem if users reuse their password, but SSL should be a base layer of protection to your users.
While it is possible to use Django templates with Django Rest Framework (DRF) as the backend, you are not limited to using Django for your front-end. Consider AngularJS with DRF. Anyways, there is a significant learning curve for AngularJS, but you needn't limit yourself to having Django supply your front-end.
As far as removing the DRF BrowsableAPIRenderer, you will get some protection from "security through obscurity", but you really need to lock down your APIs through a proper permission model as an attacker can easily look at traffic generated by your front-end to your back-end and then manipulate the requests to your back-end. So, discoverability of your interface by an adversary will not be significantly reduced through getting rid of BrowsableAPIRenderer. It will only obscure back-end resources that your front-end isn't currently using and it will also make your life as a front-end dev a little more painful.
For DEFAULT_PERMISSION_CLASSES, take a gander at DRF permissions documentation. If you only have two user groups - logged in/authenticate and not logged in, then IsAuthenticatedOrReadOnly is a good place to start. If you start to have per-model permission bifurcation for different user groups, then
DjangoModelPermissions is a good place to dig into.

AngularJS and Django REST framework cookies

I have a problem regarding AngularJS using Django as backend. The Django framework has its authentication system, using its csrftoken.
The thing is, that over the client side, i need to make sure that the client is logged in, to let him see AngularJS' views. The problem is that the $cookieStore returns undefined when asking for the Django cookie ( $cookieStore.get('csrftoken'); ).
Currently i'm adding the auth token, by sending it in the response body from the server ( $cookieStore.put('authToken', responsePody.session_key) )
After adding the cookie 'manually', i'm manipulating it (removing when user logs out etc..)
My question is how can i access the Django cookies using cookieStore, or if there is a better way of implementing this?

Right Auth with AngularJS, Django and external API service

I'm developing my first AngularJS application with Django as backend.
My overall architecture is composed of:
Public API json-rpc server (from which I must retrive data previous authentication process (the client send a user/password with a POST request, and then, the server response with a token string).
Django framework, I use this because I need to have some models and MySQL db for additional data; and because the Public API server doesn't support CORS (is a old version) and I've created an API Proxy with one view of Django.
Angular JS App that it served by Django.
Now, when the client first send user/password with AngularJS -> Django -> API server, the server respond with token, and henceforward the Client use token to make next requests.
My question is: What's the right approach to retain the token on the client (AngularJS) (or on Django if required) after the user did login??
Do you have any suggestion on my architecture?
Thanks in advance... and... sorry for my English :)
Depending from your needs you should think about storing the token in the session storage in the local storage or in a cookie(in this case the cookie is used as a storage mechanism and not as an authentication mechanism).

Multiple backend servers accessible from a Flask server

I want to have a front-end server where my clients can connect, and depending on the client, be redirected (transparently) to another Flask application that will handle the specific client needs (eg. there can be different applications).
I also want to be able to add / remove / restart those backend clients whenever I want without killing the main server for the other clients.
I'd like the clients to:
not detect that there are other servers in the backend (the URL should be the same host)
not have to reenter their credentials when they are redirected to the other process
What would be the best approach?
The front-end server that you describe is essentially what is known as a reverse proxy.
The reverse proxy receives requests from clients and forwards them to a second line of internal servers that clients cannot reach directly. Typically the decision of which internal server to forward a request to is made based on some aspect of the request URL. For example, you can assign a different sub-domain to each internal application.
After the reverse proxy receives a response from the internal server it forwards it on to the client as if it was its own response. The existence of internal servers is not revealed to the client.
Solving authentication is simple, as long as all your internal servers share the same authentication mechanism and user database. Each request will come with authentication information. This could for example be a session cookie that was set by the login request, direct user credentials or some type of authentication token. In all cases you can validate logins in the same way in all your applications.
Nginx is a popular web server that works well as a reverse proxy.
Sounds like you want a single sign-on setup for a collection of service endpoints with a single entry point.
I would consider deploying all my services as Flask applications with no knowledge of how they are to be architected. All they know is all requests for resources need some kind of credentials associated with them. The manner you pass those credentials can vary. You can use something like the FAS Flask Auth Plugin to handle authentication. Or you can do something simpler like package the credentials provided to your entry service in the HTTP headers of the subsequent requests to other services. Flask.request.headers in your subsequent services will give you access to the right headers to pass to your authentication service.
There are a lot of ways you can go when it comes to details, but I think this general architecture should work for you.

Categories