Foreman bcrypt password default cost

Hello,

I am working on a patch which replaces SHA1 hash with more safe bcrypt. This algorithm was designed for passwords, it has a “cost” complexity setting which can be increased as computers gets faster. Recommended cost value by 2018 is number of 10, but that adds about 60 ms of processing time for login action and for session-less API calls compared to SHA1. From my testing on my CPU from 2017 (AMD Ryzen 1700) cost values 6, 7, 8 and 9 add 4ms, 7ms, 15ms and 30ms.

As part of my PR, I am adding new “calibrating” seed code. Everytime rake db:seed is performed, cost value (Global setting) is recalculated to highest possible number which can be calculated below specified threshold.

Now, the question is what to set as the threshold, therefore default cost value. In my current proposal, I suggest 5 ms which is cost 6 on my CPU today. It is below recommened value for today’s CPUs which is 10 but it is still safer (slower) than SHA1 which can be calculated in less than 0.4 ms.

This is all about the tradeoff - better security by default vs slower performance of login attempt (possible DDoS attack) and session-less API. So here comes a poll and feel free to comment on the topic.

  • cost 6 (4 ms)
  • cost 7 (7 ms)
  • cost 8 (15 ms)
  • cost 9 (30 ms)
  • cost 10 (61 ms)
  • cost 11 (123 ms)
  • cost 12 (250 ms)
  • cost 20 (one minute - just for the record)
  • close the PR and keep using SHA1

0 voters

The PR is here: https://github.com/theforeman/foreman/pull/5633

One solution would be to add new flag to user table called “API user” or something like that. When checked, hashing algorithm would be SHA1 for fastest possible session-less API performance. But it is a bit clunky.

I think if the result is that we are actually using a weaker hashing due to this change compared to SHA1, then there is no point in making the change. If I understand correctly, anything under 10 isn’t considered secure at all today. (I couldn’t find a comparison of what cost gives similar security to SHA1)
If the result is that to get stronger hashing we need to make all api calls take an extra 100ms+ I would be be against this - scripts such as ansible inventory can make thousands of calls to the API, so this will add multiple minutes to the runtime.

But that’s not the case, bcrypt with cost 1 is still stronger than SHA1. We are using incorrect hash for the purpose, SHA was designed to be fast, bcrypt was designed to be as slow as you want.

So in short, bcrypt is designed to be slow but you can set how slow you want it to be. That’s the key point. I did terrible job in explaining this, let me post few links:

https://blog.novatec-gmbh.de/choosing-right-hashing-algorithm-slowness/

https://blog.codinghorror.com/speed-hashing/

It seems to me that if it’s really important to lock down Foreman passwords, users would use LDAP other than our self-baked authentication, right? This kind of means that Foreman passwords should be reasonably secure but not Fort Knox secure.

Could we allow users to choose the cost with a sensible default? The cost value could be per user and thus enable admins to choose how difficult a certain user’s password is to brute-force.

That’s exactly what the patch does. Cost is set to value not longer that 5 ms to perform hashing on initial seed and user can change it to any cost value using Administer - Setting later on.

Since most of the voters are for slower performance but increased password security by default, I propose to add new flag to user model: “Fast password hash” with explanation that this boolean can be used for session-less API users. This would keep the possibility to use SHA (opt-in only).

Why don’t we keep personal access tokens (that are random generated strings & salted) on sha1 (for fast access) and just move passwords to bcrypt?

If you use sessions, which I think you can do with the API as well, is there a performance hit on later requests?

If the risk is DDOS / bruteforce, wouldn’t a max-attempts / fail2ban style of protection be a good idea? Then the cost doesn’t need to be too high.

Because lots of users are using hammer -u admin -p change and this command is sessionless AFAIK. Password hash is verified each request. You can use hammer login to create a session but that’s not what users always do I guess.

Nope, creating an API session no longer requires password verification of course.

We already have that feature by the way, so it is not that of a problem yeah. Scratch that, the only issue is session-less API.

My biggest concern are regressions after upgrade. Once password is changed for an API user, that can start burning more CPU without a warning.

1 Like

Guys, results are rather vague, we have no clear winner. But I can still read some result: most of you want cost 10-12 while I was leaning towards cost 6 and since cost 10 is recommended on wikipedia as of today, I am rebasing the PR so the calibration sets default cost to burn at least 50ms which is cost 10 on my modern CPU from 2017.

Let’s just merge this and if we will have anybody complaining about slow session-less API, workarounds are trivial (use a session or change password via Rake Console with lower cost).

Any other comments? The PR is still pending merge. I believe this is a nice to have:

https://github.com/theforeman/foreman/pull/5633

1 Like