Django - CSRF Tokens for authenticated and unauthenticated users? - django

I was wondering if CSRF tokens for Django are generated automatically for both authenticated users and unauthenticated users? I am curious because I would like to make an API for posting form data so that any user -authenticated or unauthenticated users can be able to make a post call to the API endpoint. But I was wondering if I have to "attach" the CSRF token to the header for each user? (Implying that unauthenticated users would also have a CSRF token)

Both authenticated and unauthenticated users require a valid CSRF token when using Django's default authentication mechanism. The token is rotated when a user logs in.
Whether you need a token isn't so much dependent on if the user is authenticated, but it is dependent on the authentication mechanism. If the authentication uses sessions/cookies to authenticate the user, an attacker may use the session information that's implicitly send with each request to forge a request and perform some action that the victim is authorized to do. On the other hand, if you use e.g. token authentication, the token has to be send explicitly with each request, and an attacker can't know the token or forge a request that uses the token.

Related

Django Session Auth and DRF Knox JWT

I have an API from which users can login to get a token so they can make requests, etc and I have also made a a session login as there are a few scenarios where I need the user session token. Now if a user logs in to the API and afterwards they need to login using the session Auth its all good however the reverse does not work. If you are logged in using session Auth and then want to login via the API to release a token I get a response of Forbidden. Could someone please offer some insight?

When to call gettoken, refresh token and verify token by user in jwt in DRF?

I have been using built in token authentication for my projects in Django rest framework. But now I am shifting to simple jwt. But I am confused on one thing.
In Token Authentication user if logged in from front end returns a token, but in jwt documentation I have seen three requests as follows:
urlpatterns = [
url(r'^auth-jwt/', obtain_jwt_token),
url(r'^auth-jwt-refresh/', refresh_jwt_token),
url(r'^auth-jwt-verify/', verify_jwt_token),
]
I dont quite understand these requests. As a normal user, when a user visits a site he doesn't ask to get token, refresh token and verify token, he simply logs in and uses the features of the site. So, I am asking when these requests are made?
I hope I have explained well.
The usual flow of JWT authentication goes likes this:
The client will send a POST request with the authentication credentials, which need to be verified. If the credentials are valid the server needs to return JWT Token and a refresh token. This process is handled by the url(r'^auth-jwt/', obtain_jwt_token) URL.
The token returned after authentication is a short-lived token and to continue the user session, the client needs to get a new token using the refresh token.
This is done by url(r'^auth-jwt-refresh/', refresh_jwt_token) URL.
The third URL is not always required. You can use it to validate your JWT token in case it's required by your application.

How to authenticate the user on his requests after login in django using TokenAuthentication from drf

I have implemented an endpoint for login, using the django-rest-framework and TokenAuthentication. What i want, is after the login, the user to be authenticated and can navigate on the website.
I know that any get request on any protected using authentication uri should contain the token in the headers, so that the user can be authenticated. Everything is fine with that, if i could do all the get requests adding the token manually.
But what i do not understand is, how can i add the token in the headers when for example the user manually does the request by writing the url?
Let's say that the uri /api/ is protected and requires an authenticated user.
The user logs in, and i save the token either on the cookies or in the localstorage.
Now the user does a http get request on /api/. The token is not placed in the headers, so the response is: "Not authenticated".
So the question is, how can i add the token on any subsequent request after user logs in successfully? Maybe the backend could check the cookies for a valid token, but isn't there any better and safer solution than this?
As I believe from the question you want to add the token to all API which is consumed by your client whether App/Web. So in both people prefer to store that token either in cookies or in local storage. Once user logged out api consumer also flush that key.

django rest framework - session auth vs token auth, csrf

I have DRF set with the default settings. My ajax clients works fine with the session authentication. I want another remote server to consume the same API as the javascript clients.
My login code is simple:
class Login(APIView):
def post(self, request, *args, **kwargs):
user = authenticate(username=username, password=password)
if user is None:
return Response(status=status.HTTP_401_UNAUTHORIZED)
login(request, user)
# ...
The issue is when I use a client from another host, like python requests, I get a CSRF error. According to DRF docs, I think I should use a token authentication instead.
Questions:
Why do I need token authentication? The sessionid cookie is already a token, why I can't use it both for ajax clients and software clients? Thus avoid another separate db table for the tokens.
Since I do want to use only session authentication, how to enforce CSRF only for ajax clients?
It's not really compulsory to use Token Authentication, just that Session Authentication is liable to CSRF attacks. You can try to prevent this using CORS mecahnisms and CSRF tokens but it is still not entirely safe.
To be honest, Token Authentication doesn't entirely work well with browsers either as the token can be easily retrieved using the browser's developer tools if you don't use a very complex and sophiscated mechanism for handling it. It's just simpler to use it for third-party apps.
Though CSRF attacks are only applicable to browsers(Ajax clients), you shouldn't try to exlude them because the method of checking if the request is from an ajax client request.is_ajax() depends on whether the client has set the X-Requested-With header. It may be possible for an attacker to remove this header. Again I would advise that you also add CORS verification which is the method used by browsers to safeguard against CSRF attacks in addition to Django's CSRF tokens. This is typically done using Django-cors-headers package
And why token authentication isn't subject to csrf attacks? It does not seem more secure to me than the session. As I see it, both of them use HTTP headers to pass a token (in token authentication is in the Authorization header, and session is a cookie which is also a header)
Tokens are sent using the Authorization header(you could also decide to use a custom header but this is the standard for interoperability) while session auth uses cookies which are automatically sent by the browser and this is why they're susceptible to CSRF attacks. For tokens, the client has to explicitly set the header so it has to know the token, while the attacker will not even have to know what is stored in the cookies as the browser just automatically sends whatever is in its cookie store for that site.
You shouldn't enable CSRF protection for ajax clients only – it doesn't make any sense. How can you differentiate between "ajax" client and "normal" client? If it will be done e.g. by some query param, then an attacker can just use this "normal" link to do bad things.
When you're using token-based authentication, an attacker cannot just use common URL to make your request be authenticated transparently. That's why only session-based authentication requires a valid CSRF token to be included into request.
So for security reasons there are 2 options:
either use session-based authentication, but then you need to send auth cookie and CSRF token with every request;
or use token-based authentication, which is simpler since you only need to provide auth token e.g. as a query param.
Can I use token authentication that gets the token from the standard django_session table? just use that as token?
In theory you can achieve that by writing some custom authentication middleware that will use token from query param and match it with session table, but that's generally bad idea.
First, there's no such a big overhead in using one more table, but without it you're making the system harder to read and maintain.
Second, it will make the system more fragile as well. Since sessions and tokens are 2 completely different entities, they can have e.g. different lifetime. Sessions can be flushed, their TTL can be shorter/longer than token TTL. For example, default django session TTL is 2 weeks. Do you want to complicate remote server logic to get new token every 2 weeks? Or imagine the situation when token is compromised. Do you want to force ajax client to log out as well?

Working with django rest framework to authenticate a user with new token for every login

I would like to use django-rest-framework token to authenticate users. My workflow would be:
User requests a page
If auth token is present, respond with the requested data.
If auth token is not present, redirect to the login page (with the request page).
Inside the login page, user submit their credentials
If credentials were correctly authenticated, get or create a token for that user and redirect back to the requested page with the token.
Else, respond with error.
Lastly,
When the user logs out, delete the token for that user.
So my question is, is it okay to delete and create a new token for every login if the user has already logged out? Also I assume the token will be unique, am I correct? Your help and guidance is very much appreciated. Thank you.
A REST API should be stateless, that means that there should not be a "session" hence no login and no logout, and no redirections to a login page.
If the request doesn't have a token then the API should return (probably) a 401 Unauthorized HTTP status code and not a redirection. You're making an API so there won't be human interaction. Django rest framework offers a human-friendly interface that does have sessions, login/logout, and if that's all you need the go for it, you can do whatever you want. But It'd be hard for another program to use your API.
why not using tokens with expiration dates or using another well known authentication method ?? :P
Hope this helps :)