cache_key = sha(sha(id + username) + bcrypt(pass))
with sha256 or something.Okta Bcrypt incident lessons for designing better APIs
31–40 of 169 posts
Re: Okta Bcrypt incident lessons for designing better APIs
#32Earlier quoted context omitted.
I guess because they didn't anticipate this flaw.
Also prehashing opens you up to an other bcrypt flaw you need to be aware of: it stops at the first NUL byte, so you need to use some sort of binary-to-text encoding on top of the hash to ensure you don't have any of those in the data you ultimately hand off to bcrypt.
Re: Okta Bcrypt incident lessons for designing better APIs
#33That is such a rookie mistake. It's not some hidden information that bcrypt has a 72 char limit. Pretty widely documented in multiple implementations and languages. How does a company whose only job is security screw that up so badly?
Re: Okta Bcrypt incident lessons for designing better APIs
#34That is such a rookie mistake. It's not some hidden information that bcrypt has a 72 char limit. Pretty widely documented in multiple implementations and languages. How does a company whose only job is security screw that up so badly?
On the other hand, why not have implementations assert if they are given a string longer than 72 chars? It feels to me like no-one would ever do that on purpose, so it's a massive issue which is easy to accidentally make with a really important function.
Silently truncating the data is about the worst way to deal with it from a security standpoint. No idea why that decision was made back in the day.
Re: Okta Bcrypt incident lessons for designing better APIs
#35Earlier quoted context omitted.
Yeah, I think both of the following would have worked if they wanted the password involved in a cache key and they wanted bcrypt to be used: * bcrypt(SHA-512(PW || stuff)) * SHA(stuff || bcrypt(PW)) Disclaimer: Not cryptography advice. It's still unclear to me why the password is in there.
hmac-bcrypt solves that problem very well, and should replace plain bcrypt: https://github.com/epixoip/hmac-bcrypt
(I need that "man standing up in the town hall meeting" meme for this.)
Just use a real KDF, if that's really what you want. I'm still confused what password-derived material is doing in a Redis key.
Re: Okta Bcrypt incident lessons for designing better APIs
#36I am curious why bcrypt was used for hashing in the first place and not something like sha-512 Is there a reason I might be missing?
There is a discussion about that on the security stackexchange ( https://security.stackexchange.com/questions/133239/what-is-... ). The TLDR: > SHA-2 family of hashes was designed to be fast. BCrypt was designed to be slow. Slow == harder to brute-force == more secure.
Re: Okta Bcrypt incident lessons for designing better APIs
#37Earlier quoted context omitted.
Author here: thanks for reading the post. It's great to hear that Zig covered both cases. However, I'd still prefer the opposite behavior: a safe (without truncation) default `bcrypt()` and the unsafe function with the explicit name `bcryptWithTruncation()`. My opinion is based on the assumption that the majority of the users will go with the `bcrypt()` option. Having AI "helpers" might make this statistic even worse…
`bcrypt()` is bcrypt as implemented everywhere else, and is required for interoperability with other implementations. If you don't truncate, this is not `bcrypt` any more. `bcryptWithTruncation()` is great for applications entirely written in Zig, but can create hashes that would not verify with other implementations. The documentation of these functions is very explicit about the difference. The verification functio…
Re: Okta Bcrypt incident lessons for designing better APIs
#38That is such a rookie mistake. It's not some hidden information that bcrypt has a 72 char limit. Pretty widely documented in multiple implementations and languages. How does a company whose only job is security screw that up so badly?
On the other hand, why not have implementations assert if they are given a string longer than 72 chars? It feels to me like no-one would ever do that on purpose, so it's a massive issue which is easy to accidentally make with a really important function.
Re: Okta Bcrypt incident lessons for designing better APIs
#39Earlier quoted context omitted.
Author here: thanks for reading the post. It's great to hear that Zig covered both cases. However, I'd still prefer the opposite behavior: a safe (without truncation) default `bcrypt()` and the unsafe function with the explicit name `bcryptWithTruncation()`. My opinion is based on the assumption that the majority of the users will go with the `bcrypt()` option. Having AI "helpers" might make this statistic even worse…
Note that the "safe" version makes very bespoke choices: it prehashes only overlong password, and does so with hmac-sha512 (which it b64-encodes). So it would very much be incompatible with other bcrypt implementations when outside of the "correct space". These choices are documented in the function's docstring, but not obvious, nor do they seem encoded in a custom version.
So something like crypto.danger.bcrypt and crypto.bcryptWithTruncation
Re: Okta Bcrypt incident lessons for designing better APIs
#40Earlier quoted context omitted.
hmac-bcrypt solves that problem very well, and should replace plain bcrypt: https://github.com/epixoip/hmac-bcrypt
I don't think it's a good idea for people to adopt new bcrypt constructions so that they can use it to generate cache keys (or, worse, other keys). (I need that "man standing up in the town hall meeting" meme for this.) Just use a real KDF, if that's really what you want. I'm still confused what password-derived material is doing in a Redis key.