Live data from Hacker News

Okta Bcrypt incident lessons for designing better APIs

n0rdy.foo

91–100 of 169 posts

Re: Okta Bcrypt incident lessons for designing better APIs

#91

what I would have naturally done without anticipating any flaw (and probably be just OK): cache_key = sha(sha(id + username) + bcrypt(pass)) with sha256 or something.

Why not a simple sha(id + username + bcrypt(pass))

Is there any security issues with that? I'm a "newb" in this area, so I'm genuinely curious about the flaws with the naive approach

Re: Okta Bcrypt incident lessons for designing better APIs

#92
post #55
post #45

Earlier quoted context omitted.

I feel like the "authentication company should have known" thing is unuseful; most developers at "security" companies are just ordinary generalist developers. Ironically, I think they boned themselves by trying to be too clever here, not too casual.

You don't think a company whose entire reason for being is providing security services for other companies should have designs related to authentication reviewed by security experts?

Ship early, ship often, we can add security later.

Re: Okta Bcrypt incident lessons for designing better APIs

#93

Earlier quoted context omitted.

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.

It is almost never I good idea to assert in a library, unless the error is truly unrecoverable. I think returning an error code\throwing an exception would be very reasonable and a much better API than failing silently though.

Honestly, I would assert. Returning an error code just gives users another thing to ignore, and incorrectly use the return value (if implemented like C, where you usually get a single internet back, treating the error code as a hash would be even worse!)

Apps crashing with assets is awfully, but at least it screams at your when you failed to read the docs, target than incorrectly storing users data for the rest of time.

Re: Okta Bcrypt incident lessons for designing better APIs

#94

Hold on, in the Rust example, how does `err_on_truncation` get set? TFA completely ignored that there's a setting somewhere (probably incorrectly defaulting to false)

In the bcrypt crate there is an explicit method for it:

    bcrypt::non_truncating_hash() 
https://docs.rs/bcrypt/latest/bcrypt/

Funnily, TFA later also suggests that such function should exist...

Re: Okta Bcrypt incident lessons for designing better APIs

#95

This is a completely unreasonable API. It reminds me of the `mysql_real_escape_string` vs. `mysql_escape_string`. The default API must be the strict one. You should be able to configure it to be broken but silent truncation is an insane piece of functionality. There is no universe in which this is logical. One might as well just have everything return void* and then put in the documentation what type to cast to. The…

Seriously, the number of “you weren’t meant to fire that foot gun” defenses in this thread…

Re: Okta Bcrypt incident lessons for designing better APIs

#96
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;…

> I've in the past been annoying about saying I think we should just call all password hashes "KDFs"

I remember :-): https://news.ycombinator.com/item?id=42899432

Re: Okta Bcrypt incident lessons for designing better APIs

#97
post #35

Earlier 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.

By cache they mean cached credentials.

>The user previously authenticated creating a cache of the authentication

Maybe, it's a password encrypted secret token.

Re: Okta Bcrypt incident lessons for designing better APIs

#98
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;…

Unfortunately the industry defined Bcrypt as a KDF for some time, even though it is better named as a "password hashing function". Cryptography has a history of being bad at picking good names for new work.

In addition to (true) KDFs, people often want a HKDF (HMAC-based Key Derivation Function) or hierarchical deterministic key derivation function (HDK).

Re: Okta Bcrypt incident lessons for designing better APIs

#99
post #55
post #45

Earlier quoted context omitted.

I feel like the "authentication company should have known" thing is unuseful; most developers at "security" companies are just ordinary generalist developers. Ironically, I think they boned themselves by trying to be too clever here, not too casual.

You don't think a company whose entire reason for being is providing security services for other companies should have designs related to authentication reviewed by security experts?

Cybersecurity != security in the technical/mathematical sense. It's related, but not the same.

For businesses, cybersecurity is (like everything else, ultimately) about minimizing costs related to digital threats. That is - any threat scenario can be modelled as T*D, where T is "how likely it's going to happen (per year)", and D is "how much it'll cost us when it does (per incident)"; the result is the expected yearly loss, denominated in dollars. The less of it you have (integrated over all scenarios you can think of), the better, but prevention and mitigation also cost money, so what you're actually minimizing is the (expected loss + mitigation costs); i.e. makes no sense to spend more on improving something than it'll save you.

The reason for this exposition dump is: actual security at the technical level is one of many ways of improving TxD, and usually is neither cheap nor the most interesting one. It's also mostly focused on the "T side" (minimizing risk of an incident), which is harder to move than the "D side" - reducing impact.

The service an authentication company is selling is not "cryptographically unbreakable authentication". What they're selling is roughly: "low-T auth sytem cheaper than you could build&operate yourself + if it breaks it's our fault". That is, more than lowering "T side", they're offering to let you shift part of the liability to them, which significantly lowers "D side".

Internally, how they do it is up to them. But there's only so much need for technical security experts - you obviously can't sell a broken system (everyone has to at least pay a lip service to real security, otherwise people get angry, politicians get interested, and costs start to multiply rapidly), but eventually, it's cheaper to focus on your ability to take on liability from your customers and discharge it somewhere else, which involves improving operations, customer service, etc. - all the stuff you need regular, non-security-expert programmers for.

Note the bit about discharging liability. After working in cybersec and GRC for a bit, I realized security is best understood in terms of managing liability (which corresponds to minimizing the D part of TxD from earlier). That's the primary product of most security service companies, as well as security frameworks and associated compliance audits. They do improve the technical side somewhat too, but that's not why those things are bought. They're bought so, when something happens (something eventually always happen), you could point at the SOC.2 audit results and a string of security contracts and say, "we've followed all the best practices, there was nothing more we could do; crime happens, not our fault" - and have the liability flow down the contractual agreements to other companies, which do the same, until, like spring rain flowing down the mountains, into rivers, into sea, it all gets turned into insurance payouts in the end :).

Might sound cynical, but it's probably the right and reasonable thing to be happening 90% of the time. Shit happens, criminals be criminals, opportunity costs are real, etc.

Re: Okta Bcrypt incident lessons for designing better APIs

#100
post #47

I can see the incident was a jumping off point to talk about bad APIs (bcrypt probably should error >72) but it sounds like the actual bug was they weren't checking the value in the cache matched the data they used in the hash for the key. The authentication cache check should survive any arbitrarily bad hashing algorithm because all of them are going to have collisions (pigeonhole principal). Even an arbitrarily 'st…

Something similar happens in my company too. In a particular place, we use the hash of a string as the key in a hashmap instead of the string itself, because the hash is smaller and is easier to compare after the initial map has been made. It is a 64bit hash too. I have been crying about this everytime it comes up, and the response is, it will never happen. My problem is that we will never know if it ever happens too…

Isn't a hash map supposed to already be internally hashing the string for you and correctly handling collisions?
Post reply on HN