Live data from Hacker News

Okta Bcrypt incident lessons for designing better APIs

n0rdy.foo

11–20 of 169 posts

Re: Okta Bcrypt incident lessons for designing better APIs

#11
post #2

The bcrypt implementation in the Zig standard library has both the bcrypt() function (where truncation is explicitly documented) and the bcryptWithoutTruncation() function (which is recommended and automatically pre-hashes long passwords).

Disappointing that Zig would get the API design wrong too. I would have expected better.

If you don't see the mistake, Google 'yaml.safe_load'.

Re: Okta Bcrypt incident lessons for designing better APIs

#12
post #3

Bcrypt is a password hash, not a KDF, which is the way it was used in this API. It's super unclear to me why they wanted a string-based KDF here at all; does anyone have more context? I've in the past been annoying about saying I think we should just call all password hashes "KDFs", but here's a really good illustration of why I was definitely wrong about that. A KDF is a generally-useful bit of cryptography joinery;…

The value is the combination of userid, username, and password, so in threads on other platforms people have hypothesised that the developer tried to play it safe and use a password hash because of the password's presence.

Also I'm not sure the average developer understands the distinction.

Re: Okta Bcrypt incident lessons for designing better APIs

#14
post #8

I 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?

Yes, the hashed payload contained a password, so presumably they didn't want to just SHA it.

But why not bcrypt the password, but sha the cache key on top?

Re: Okta Bcrypt incident lessons for designing better APIs

#15
post #4
post #2

The bcrypt implementation in the Zig standard library has both the bcrypt() function (where truncation is explicitly documented) and the bcryptWithoutTruncation() function (which is recommended and automatically pre-hashes long passwords).

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.

Re: Okta Bcrypt incident lessons for designing better APIs

#16
post #8

Earlier quoted context omitted.

Yes, the hashed payload contained a password, so presumably they didn't want to just SHA it.

But why not bcrypt the password, but sha the cache key on top?

I guess because they didn't anticipate this flaw.

Re: Okta Bcrypt incident lessons for designing better APIs

#17
post #8

I 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?

Yes, the hashed payload contained a password, so presumably they didn't want to just SHA it.

Begs the question of why the payload contained a password, right?

Re: Okta Bcrypt incident lessons for designing better APIs

#18
post #3

Bcrypt is a password hash, not a KDF, which is the way it was used in this API. It's super unclear to me why they wanted a string-based KDF here at all; does anyone have more context? I've in the past been annoying about saying I think we should just call all password hashes "KDFs", but here's a really good illustration of why I was definitely wrong about that. A KDF is a generally-useful bit of cryptography joinery;…

They didn't want a KDF, as far as I know, but they wanted a hash function with unlimited input size.

Including the username in the hash input gives you guaranteed domain separation between users that you don't get from salts/nonces. Its a generally good idea if you have a hash function with unlimited input size (all modern cryptographic hash functions except bcrypt have unlimited input size).

Re: Okta Bcrypt incident lessons for designing better APIs

#19
post #13

That 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?

> How does a company whose only job is security screw that up so badly?

While I don't have any answers to this, I've realized that it's an ideal showcase of why fuzzy testing is useful.

Re: Okta Bcrypt incident lessons for designing better APIs

#20
post #3

Bcrypt is a password hash, not a KDF, which is the way it was used in this API. It's super unclear to me why they wanted a string-based KDF here at all; does anyone have more context? I've in the past been annoying about saying I think we should just call all password hashes "KDFs", but here's a really good illustration of why I was definitely wrong about that. A KDF is a generally-useful bit of cryptography joinery;…

They didn't want a KDF, as far as I know, but they wanted a hash function with unlimited input size. Including the username in the hash input gives you guaranteed domain separation between users that you don't get from salts/nonces. Its a generally good idea if you have a hash function with unlimited input size (all modern cryptographic hash functions except bcrypt have unlimited input size).

They clearly wanted something stronger than "a hash function" or they'd have reached for weaker cryptographic hashes.
Post reply on HN