aaronn / django-rest-framework-passwordless

Passwordless Auth for Django REST Framework
MIT License
708 stars 153 forks source link

Custom token length? #87

Open Myzel394 opened 3 years ago

Myzel394 commented 3 years ago

I think a token length of 6 is not secure. It would be nice to have the ability to change the length of the token (and maybe completely change the token? I think alphanumeric would be better).

If my calculations are correct, a hacker has a pretty good chance of getting the right token.

You can calculate the entropy using the formula: log(uniqueCharactersAmount^Length) / log(2)

The entropy of the password is: log(10^6) / log(2) = 19.9315 So about 20 bits.

With the formula: 2^(entropy - 1) / requestsPerSecond

you can calculate the duration it takes to crack the token. According to this site, django can handle about 15,000 requests per second, but a production server has middlewares, logging, etc. Let's just work with 500 request per second.

2^(20 - 1) / 500 = 1,048.576 ~ 17.5 Minutes

15 / 17.5 is about 0.85 - so a hacker has a 85% chance of finding the right token.

If we'd use alphanumeric (62 characters), it would take about 397 days to bruteforce all of them!

But anyway, just my two cents and I probably screwed the maths up :D

charleshan commented 3 years ago

A better approach to solving this problem is to lock the account for X minutes after Y attempts. Another solution is rate-limiting. Making a one-time password more complicated is not an elegant solution, especially for the non-tech audience.

If you still want to go this route, there's a pull request for configurable token length although you'd probably have to make some adjustments because the max length is set as 6: https://github.com/aaronn/django-rest-framework-passwordless/pull/86

Myzel394 commented 3 years ago

Locking an innocent account is a very bad idea (my school used to do that and from time to time a hacker would just lock all accounts by using incorrect tokens. No one, not even the admin, could login into their accounts!).

Rate-limiting is actually a good idea! Setting a limit of e.g 1/second would let someone only guess 900 tokens in 15 minutes - only 0.09% of all possible tokens!

aaronn commented 3 years ago

I think rate-limiting is the way to go here.

Myzel394 commented 3 years ago

I just heard about Microsoft's newest security fix, and I think rate-limiting is not the solution. Afaik drf rate-limits per ip adress, but this is vulnerable (see https://thezerohack.com/how-i-might-have-hacked-any-microsoft-account).

I think it would be better to store the amount of attempts per token, and after... let's say 10 attempts (this should be customizable of course) the user receives a new token. What do you say @charleshan and @aaronn ?

zsoltbalint commented 2 years ago

Generating a new token after X attempts has some issues. Let's say X is 10. This means after 10 attempts, the owner of the account will receive an email with the new token. Even worse if the user will receive an SMS. The user will hate the site and the site will also be backlisted from different email providers. In case of SMS, the site owner will pay a lot of money for Twilio.

Myzel394 commented 2 years ago

@zsoltbalint Yes you're right, I didn't think of that. A better solution would be to rate-limit per account (as rate-limiting per ip is vulnerable, see my comment above)