[Django]-Django rest framework – session auth vs token auth, csrf

6👍

  1. 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.

  2. 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.

2👍

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?

Leave a comment