Hashing tokens with django rest - python

I am creating a REST API with django-rest-framework. The framework supports token authentication but this feature does not seem to be very robust. For example, I would like to hash the tokens before they are inserted in the DB as well as add a salt.
Can I hash and salt a token with the authentication mechanism in django-rest?
Thanks

Make use of django-rest-framework-jwt. It's a modern way of authentication and doesn't require any DB operation. Also you can send some data to front end like the roles and other non secure user information.

Related

How to safely send a user data in API call

Created a Flash Restful API with various end points for my website. Some endpoints need the users username and password to get user specific data. I’m currently sending these as parameters in the API call but I’m assuming this isn’t secure so how does one do this safely?
There are plenty of differing ways to do this but it's generally accepted that using tokens, which can be revoked, are a more secure way of doing auth than using a username/password combo. This is due to the inability to retract a username/password if they got leaked.
I'd suggest reading the following blog by Miguel. He explains password authentication followed by tokens.
Miguel Grinberg
you can make a seperate api route that acts as a login and returns a sessionID/token on a successful login that can be used for authenticating to those endpoints you mentioned.

Implementing CSRF protection in a Python REST API

Writing a REST API with Pyramid/Cornice using JWT for authentication, I'll have to implement some CSRF protection.
Having thoroughly read up on the topic I understand the problem, but I'm pretty confused about the best way to implement it, it's a bit tricky considering all the possible attack vectors.
Since this API gives access to sensitive data and will be published as open source software, it requires a self-contained protection. It will be used in environments with untrusted subdomains and I can not rely on users to follow security guidelines.
For my stateless service I can either use "Double Submit Cookies" or the "Encrypted Token Pattern"-method.
Double Submit Cookies
To prevent "cookie tossing", the token in the Double Submit method needs to be verifiable. MiTM attacks are an additional threat, which I hope to mitigate sufficiently by forcing HTTPS-cookies only.
To get a verifiable token that can't be easily guessed and replicated by an attacker, I imagine a hashed token like this should work:
pbkdf2_sha256.encrypt($userid + $expire + $mycsrfsecret, salt=$salt)
"exp" is the expire-value from the JWT. The JWT will be issued together with the CSRF-cookie and "exp" can be read by the server, which adds some additional protection as it's variable and the attacker doesn't know it (Might be superfluous?).
On a request I can easily compare the two tokens I receive with each other and use pbkdf2_sha256.verify($tokenfromrequest, $userid + $exp + $mycsrfsecret) to compare it with the values from the JWT-token ('Verifiablity').
Would that approach follow recommended practices?
I've selected pbkdf2 over bcrypt since its verify-method is noticeably quicker.
Expiry would be set to 7 days, after that both the JWT and the CSRF-token would be renewed by a fresh login (They would also be renewed on an intermediate relogin).
Encrypted Token Pattern
The alternative is to send a string to the client, consisting of userid, expiry and nonce, encrypted with a server-side secret. On a request this string is sent along and the server can decrypt it and verify userid and expiry.
This seems the simpler approach, but I'm unsure how to implement it, I don't intend to roll my own crypto and I have not found good examples:
What cipher/library should I use in Python? How do I do Encrypt-then-MAC?
How would I persist the token until its natural expiration? I don't want the users to have to login freshly every time they restart their browsers. Local Storage is not a safe place - but there is no alternative.
Writing a REST API with Pyramid/Cornice using JWT for authentication
While I am not familiar with those frameworks, I suggest you ensure the JWT token is passed within a HTTP header (e.g. My-JWT-Token: ... ) which is NOT the cookie. Then you do not have to worry about the CSRF vector.
Cross Site Request Forgery is an issue due to the nature of the browser's tendency to always submit cookies, which often contain authentication information, to a particular domain. A browser will not automatically submit a custom header, ergo you do not have to worry.
Double Submit Cookies
Your method is overly complicated, you could simply use a GUID. Put that GUID in a cookie, and put it in any other part of the request. If they equal, CSRF check passed. You could also put the GUID into the JWT, then validate the GUID is also in a header/body/query parameter.
Encrypted Token Pattern
This is almost exactly what JWT is, just pass the token in the header as suggested 😄
To answer the questions:
I would suggest hmac as in import hmac. I would not bother encrypting but merely ensure there is no sensitive information in the token. Else PyCrypto may do you well.
This is why cookies exist, which does raise the CSRF issue again. If this is a hard requirement then I suggest the double submit cookie method.

HMAC Authentication using Django - Shared Secret

For those who read this later: This was part of a hobby project I was doing and back then I wasn't aware of such a thing called Let's Encrypt! Also, I didn't want to purchase an SSL cert; so I was trying to have SOME security without https. Signing does not replace encryption. If you wanna do what I wanted to do, don't. Get a cert from Let's Encrypt. It's Easier and more secure!
I am implementing a web service using Django for a mobile app. I decided to use Hash-MAC to authenticate requests (no Oath, no https) but the challenge is what should I use as the shared secret key?
First I considered using The user's password but it required to store passwords in plain text in server-side database. The other solution that came to my mind was salting and hashing password in the mobile app just the way that Django auth app does in order to compute hashed password on client-side.
What does Django use as salt? Are they "secret"? Is there any problem with sending them as plain-text to users? We don't have to keep salts as "secret"s in general, but Django may use something that should be kept secret as salts, I don't know, it is about how Django implemented this.
Users have to know their salts to compute a hashed password, so the server should provide them with it. An adversary can ask for all users salts and eventually (s)he can have all the salts (Even if there is a limit to the number of times someone can ask for this in a certain time period). Even though salts are not secret but I guess knowing "all" of them can be dangerous. (or maybe I am overly concerned about security!)
Requests format:
HTTP request header:
x-mac-digest: 1d186b9c0fd5cd393f23623f0d167f7b17ac7d1cd74d8442647991d61e756c19
HTTP request body:
{
"username": "mjafar",
... rest of request in json
}
Authenticating request (simplified):
hash_digest = request.META['HTTP_X_MAC_DIGEST']
request_body = request.body.decode('utf-8')
request_json = json.loads(request_body)
user = UserModel.objects.get(username=request_json['username'])
sharedKey = getSharedKey(user) # What should it return?
hash = hmac.new(sharedKey, request_body, hashlib.sha256).hexdigest()
if hash != hash_digest:
return HttpResponseBadRequest('MAC authentication failed')
HMAC is used to authenticate a block of messages. It's used to verify block of cipher/Text was not changed during the transmission. You will need to use asymmetric encryption (RSA, DH,..etc) to transfer your shared key.
Using a plain text without using digital signature is useless. You will be vulnerable to MITM attack. Unless you manage to put the shared secret on the mobile app without internet (GSM SIM cards have shared key inside the sim itself and it's used to encrypt GSM calls).
Django uses random function to generate its secret_key. Random function on Linux will call /dev/urandom, on windows will call what's equivalent to that.
In your case, create a rest api to create a username and password, then return a hash value to be used to access your views.
If you want to compute a custom hash value, you can call make_password function, and save it directly in the password attribute in User
Read this: https://docs.djangoproject.com/en/1.8/topics/auth/passwords/
Example: Django make_password too slow for creating large list of users programatically

How to achieve Python REST authentication

I am a newbie and I want to do the following
I have service endpoints like
#login_required
#app.route('/')
def home():
pass
#login_required
#app.route('/add')
def add():
pass
#login_required
#app.route('/save')
def save():
pass
#login_required
#app.route('/delete')
def delete():
pass
I would like user to user to be authenticated while making these calls.
Question
How can I authenticate REST calls using python?
How do I make sure that if call lands to execute any of the endpoints, they are authenticated?
How do I basically do all authentication at the HTTP header level without saving any state so that it can scale better in future (Like Amazon S3), meaning any call might go to a different server and still be able to authenticate it self.
I am entirely new to REST world and don't really know how to achieve this.
Thank you
First, a question, are you authenticating a user, a client, or both?
For authenticating a client I like HTTP MAC Authentication for REST service authentication. Take a look at the Mozilla Services macauthlib and how it's used in their pyramid_macauth project. You should be able to learn from pyramid_macauth as an example in applying macauthlib to secure your services. A search to see if anyone else has tried this with Flask is a good idea, too.
For authenticating users and clients, perhaps take a look at OAuth 2.0 proper (HTTP MAC Auth is a related specification).
I had hoped to post more links, however, this is my first post and it seems I have to earn my way to more links in a response. :)
Security is not for noobs. Use a framework and rely on its implementation. Study the source code, read blogs and papers, and at some point you'll be able to architect your own system.
There are many things that may go wrong, and once you deploy a protocol you may not be able to come back without breaking existing clients.
That said, the usual way fot authenticating a request is by using a couple of tokens, usually called a public key and a private (secret) key. A variant is using the private key to generate a short lived session token. Another variant is using an API key specific per client. Anyway, this token is usually sent in a HTTP header (either a standard cookie or a custom one), but it's also possible to use the request body. Usually they are not appended to the URL because the secret may end in a log file. Also, you should pay attention to how and where store the secret key.
Depending on the channel (plain HTTP) you may want to use a HMAC to sign requests instead of sending secrets in the wild. You have to watch against replay attacks. Timing attacks are possible. Cryptographic collisions may be used to defeat your scheme. You may need tokens to avoid CSRF (this is not really needed if web browsers don't come into play, but you don't specify this)
Again, choose a framework and don't code anything by yourself. Broken software is usually ok to fix, but security holes can do real damages.
Looking at your API, it does not look like restful endpoints. The URI should represent a certain entity and not actions. For an instance if you are dealing with an entity such as user you could have yourdomain.com/user and perform various operations such as create, delete, update and fetch using HTTP verbs like POST, DELETE, PATCH and GET (Given that you use flask this can be achieved very easily).
In terms of security, I assume there are multiple schemes but the one which I have used is generating a session token given a key and secret via an initial authenticate call. I suggest you look for specialized online resources on generating key and secret pair as well as the session token.
In terms of scaling I guess your concern is that the sessions should not be specific to a given machine. The authentication data can be stored in a store separately from the HTTP front-ends. This way you can add additional webservers and scale your front-end or add additional data stores and scale either on a need basis.

Digest authentication in django

As far as my knowledge says in digest authentication, a client does an irreversible computation, using the password and a random value supplied by the server as input values. The result is transmitted to the server who does the same computation and authenticates the client if he arrives at the same value. Since the computation is irreversible, an eavesdropper can't obtain the password.
Keeping eye on the above definition, I used CryptoJS.HmacSHA256("password", "key") in Javascript to send the information to django server, now the problem is:
I need to check that in server using same logic but django already has hashed the password in its own format, for example using pbkdf2_sha256.
Should I use some reversible algorithm like AES? I don't think it is possible to crack django's hashing algorithm and write the same for client side?
Why are you trying to do authentication in this manner? You can not use djangos default authentication for this.
What you could do though is (for example):
Create a new model, linked to the user, that has a shared secret key, and a token
Create your own authentication backend which accepts the signed value, validates the signed value, and then logs the user in
I used the details in this article to implement the algorithm. Even if you aren't using this method, you're still going to need to create your own custom authentication backend.
AES is not a hashing algorithm. It's an encryption algorithm.
You can use hashing algorithms like SHA1 or MD5.

Categories