How to have string IDs with a prefix like Stripe has?

When working with Stripe API (and dashboard), I got so used to their style of IDs.

For customer, it is something like cus_sd9f87gds987, for subscription it is sub_df987gds98fg, for invoice it is in_d98fg7d987fg, and so on. You got the idea.

The UX is so much better, especially when logging, debugging, etc. I can even imagine when doing something like MySystem.Customer.find("sub_asd8f987sdfg908") I can reject it immediately without even asking the DB, because I am sure this ID doesn’t belong to a customer but to a subscription.

I am really curious how it works internally. If those “hashes” are just numerical DB IDs transformed on-the-fly to a string and prefixed with cus_, sub_, … for better readability or if those exact values are stored in their databases. If those IDs are generated by some central service like a Snowflake, or if they are using a PostgreSQL function or something similar.

What do you think would be the best approach to have something like that in a Phoenix + Ecto app?

3 Likes

Look at this package hashids | Hex it will give you hashed ids that you can reverse back.

2 Likes

Custom implementation(s) of Phoenix.Param can handle url generation using those user facing ids.

4 Likes

I found this blog post that outlines an approach to making this work with Ecto: Dan Schultzer: Prefixed base62 UUIDv7 Object IDs with Ecto

1 Like

It’s fine to use prefixes for IDs but NEVER use them for anything you use to authenticate a user and/or API request.

It may be convenient to use the prefixes for all the reasons you mention, but will make attackers life easier when reverse engineering apps to find the what is required to connect to the backend as a legit user and/or app.

When I was doing security research I was always amazed how the big names of our industry use prefixes in secrets. It’s so dam easy to find such secrets in the binary of a mobile app. All it takes its to download the binary and use the string tool from Linux and search for the prefix.

Doesn’t that sound a bit like an attempt at security through obscurity?

As someone who worked for five years in the security space, I keep saying to everyone that Security by Obscurity is marketing from security vendors to make us buy their products, which we may need or not.

Think of castles and prisons, all of them are full of what everyone likes to call security by obscurity, but what they should be calling this is security by layers of defense, because that’s what it is in practice. It’s like an onion: how many layers do you need to peel off to reach the core? The more security layers you need to overcome, the harder it will become for the attacker to fulfil their goal, and many will give up or not even try, going instead after the low-hanging fruit elsewhere, for example, after the ones that see many things as security by obscurity and don’t have as many layers of defense or none at all.

I will reiterate. Removing prefixes from secrets isn’t even a case of adding another layer of security; it’s, in the first place, a very bad thing to do in terms of security or, if you prefer, something that shouldn’t be there in the first place.

I know, and I have experienced it more times than I wanted, that convenience, often, wins over security. Even among security people, I see them applying this mantra: Do what I tell you, not what you see me doing.