-
-
Notifications
You must be signed in to change notification settings - Fork 510
Slow token authentication #731
Comments
I suspect the database. Can you check the issued queries (with |
I don't think that it is the database. It has only two tables with one record each. However, if I run profiler for the GET method with Tue Nov 7 14:02:31 2017 /tmp/elis_api_profile/GET.root.002310ms.1510059751.prof
5125 function calls (4946 primitive calls) in 2.310 seconds
Ordered by: internal time
List reduced from 733 to 20 due to restriction <20>
ncalls tottime percall cumtime percall filename:lineno(function)
2 2.299 1.150 2.299 1.150 {built-in method _crypt.crypt}
4 0.001 0.000 0.001 0.000 {method 'execute' of 'sqlite3.Cursor' objects}
387 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance}
212/185 0.000 0.000 0.002 0.000 {built-in method builtins.getattr}
2 0.000 0.000 2.299 1.150 /usr/lib/python3.6/crypt.py:35(crypt)
91 0.000 0.000 0.000 0.000 .../python3.6/site-packages/werkzeug/local.py:160(top)
128/124 0.000 0.000 0.000 0.000 {built-in method builtins.hasattr}
12 0.000 0.000 0.000 0.000 .../python3.6/site-packages/sqlalchemy/sql/selectable.py:2749(_froms)
4 0.000 0.000 0.000 0.000 .../python3.6/site-packages/sqlalchemy/sql/visitors.py:210(iterate)
1 0.000 0.000 0.000 0.000 {built-in method _sqlite3.connect}
24 0.000 0.000 0.000 0.000 .../python3.6/site-packages/sqlalchemy/sql/compiler.py:676(visit_column)
81/40 0.000 0.000 1.144 0.029 .../python3.6/site-packages/werkzeug/local.py:300(_get_current_object)
95 0.000 0.000 0.000 0.000 .../python3.6/site-packages/werkzeug/local.py:68(__getattr__)
18 0.000 0.000 0.000 0.000 .../python3.6/site-packages/sqlalchemy/sql/compiler.py:633(visit_label)
18 0.000 0.000 0.001 0.000 .../python3.6/site-packages/sqlalchemy/sql/compiler.py:1421(_label_select_column)
4 0.000 0.000 0.000 0.000 .../python3.6/site-packages/sqlalchemy/orm/loading.py:273(_instance_processor)
67/4 0.000 0.000 0.001 0.000 .../python3.6/site-packages/sqlalchemy/sql/visitors.py:75(_compiler_dispatch)
1 0.000 0.000 0.000 0.000 {method 'close' of 'sqlite3.Connection' objects}
62/45 0.000 0.000 0.002 0.000 .../python3.6/site-packages/werkzeug/local.py:344(__getattr__)
1 0.000 0.000 0.000 0.000 .../python3.6/site-packages/werkzeug/routing.py:1253(bind_to_environ) The builtin method |
White testing your example in clean virtualenv, I have found following warning.
Can you check if you get it while importing |
I can also confirm this issue. At my work we moved away from See #663 which is the same problem, only exhibited by our test suite. Switching to |
Can you also check the performance of the build-in function separately?
( |
No warning and installing Python 3.6.3 (default, Oct 3 2017, 21:45:48)
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import passlib.hash
>>> quit() |
timeit(setup="import crypt", stmt="crypt.crypt('password', 'secret')", number=2)/2
2.0448000213946216e-05 And these are actual parameters for timeit(setup="import crypt",
stmt="crypt.crypt('$pbkdf2-sha512$25000$2hsDICSk1Pq/VyqltFZqLQ$O6TlnzzR8/U32Zpg/IGopscAvem3QbGJIXCKJCC0ZwIZpY2JcU4vgcSEsP4RVtoMpPLU5lsXEKouqdIZycbPTA', '$5$rounds=535000$CnKACJ4960/7u1F6$kWG4xrwa3E6nPaP42BhEOup3GUDhMhoHZKbsvPkeXk0')", number=2)/2
1.1937105525012157 |
The hashing scheme used by default is intentionally slow - I believe the bug is that the hash is calculated on every request, which it shouldn't be. |
I believe the same. |
@KPilnacek did you manage to work around this in any way? I'm having the same issue. |
SECURITY_HASHING_SCHEMES default to sha256_crypt
such as:
|
Having the same problem. We also have an SLA of 100 ms, and are running into the exact same issue -- around 2.4 seconds for a request, with most of that coming from crypt. |
Just a question -- you folks using Linux, on some kind of VM? Install haveged, start it, try again. |
@caalle at first, sorry for the delay. He added a custom loader to # add our custom callback for user token authorization
security.login_manager.request_loader(check_user_auth_token) In the function However, throughout our time with |
@KPilnacek thank you for providing more info. Too bad you had to switch. I'll give it some more testing before making a switch to something more lightweight. |
Came across this thread as I'm updating to Flask-Security v3.0.0 and came across this same issue. Previously, I had already accounted for skipping the slowness caused by the hashing in the login process, but now it seems intense hashing is also done when generating and checking the auth token, which happens in the majority of my tests. It seems like the "old" functionality can be restored via the following settings:
I'm sure this has security implications. But for my application, it's not worth the performance impact. I would assume the same is true for most applications. Adding a 1-2 second overhead to every authenticated endpoint is not acceptable. Is there something I/we are doing wrong here? |
(I'll preface this by saying by crypto knowledge is very basic, so anyone please correct me as needed) @mafrosis
Case #2 is what was significantly slowed down in v3 (with default settings). Case #1 is certainly important to employ a slow hashing function, to prevent brute force attacks. However, I don't see the need to slow down auth token generation/checking. Brute-forcing an authentication token seems extremely impossible, since they are such long, complicated strings. |
This is a pretty big issue that is causing more than a few people to not use or switch away from flask-security :( |
Just making a suggestion here and it seems to only be affecting API/token logins from what I am seeing from this and other threads. If this is incorrect please advise. With that assumption could a potential solution be to use a sort of session token once authentication is done. This way it then doesn't have to utilize bcrypt or one of the more robust crypto protocols so that once a user is authenticated a simpler token can then be utilized for the API calls (similar to what was used previously)? After x amount of time without usage it would expire (could also be associated with the IP that was authenticated) and the user would then need to login again and get another session token. Something similar is utilized by a file sharing app that I use for its API calls. |
this issue is quite annoying, one simple call takes 600ms+, while it takes <100ms when there was no token authentication involved. |
Install and run “haveged” and try again.
From: zhookz <[email protected]>(mailto:[email protected])
Reply: mattupstate/flask-security <[email protected]>(mailto:[email protected])
Date: March 25, 2018 at 01:14:42
To: mattupstate/flask-security <[email protected]>(mailto:[email protected])
CC: pahrohfit <[email protected]>(mailto:[email protected]), Comment <[email protected]>(mailto:[email protected])
…Subject: Re: [mattupstate/flask-security] Slow token authentication (#731)
this issue is quite annoying, one simple call takes 600ms+, while it takes <100ms when there was no token authentication involved.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub(#731 (comment)), or mute the thread(https://github.com/notifications/unsubscribe-auth/ABf0cmikTsAfxrY2pi56IrxJpn1kAN-Nks5thyfCgaJpZM4QUrF3).
|
I have the same issue... |
It's working, thank you very much! |
@jirikuncar, @lnielsen, @mattupstate any thoughts on the suggested solution by @biomap? If I understand right – and please correct me, If I did get it wrong – it is the So the goal seems to be to provide an auth token which is somehow dependent on the password (so that if users change their password it is not valid anymore, see #771). In the same time it should not directly depend on the password, because then we would have to encrypt it (time-consumingly) – in order to not risk its recreation from the token. So if there would be a token that gets created on user login, stored to a user, and removed on password change and logout, and this token would have nothing to do with the actual password, would that work? This would mean some storage/db access overhead when logging in/out + changing the password, but would entirely decouple the auth token from the password, i.e. it could be handled without a time consuming encryption. Any thoughts? We are facing this issue for quite some while now in a production app, so I’d love to get rid of it. Let me know if I can help in any way. |
Recovery code form now shows 'no recovery codes setup' if user asks to see them and there aren't any. two-factor-setup template shows existing, if any, already setup method. In docs - remove 2FA is beta - its been around a while. Yet a few more non-translated headers in templates.
Hello guys,
at my current job, I happened to be a part of a backend team, which is creating an API.
The API should be then served to javascript application and needs to be quite fast (100 ms or so).
However, it is not.
After some profiling, we figured out that it is the token authentication in
Flask-security
, which is holding us back (pleas see the MWE).MWE
Basic authentication timing
The timings are perfect (bellow 100 ms) but that is not the way we should do it.
Token authentication timing
Getting the token is OK.
But than the request is terribly slow.
The timings are 20 times slower 😳 😮.
What with that???
I know that
Flask-security
wraps together several other flask security packages (Flask-login
,Flask-WTF
, ...).Flask-security
orFlask-login
or something deeper?)However, it might not be necessary to do it every time.
It should be enough, to only store the token and check if the incoming token is the same as the stored one.
Is there a way to do it like that (either with
Flask-security
or not)?app.config
) a different way to make it faster (still using the token auth.)?Flask-security
)?Flask-security
holding us back?I have cross-posted this issue on StackOverflow.
The text was updated successfully, but these errors were encountered: